@socketsecurity/lib 6.0.8 → 6.0.10
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 +28 -0
- package/README.md +8 -9
- package/dist/abort/signal.d.ts +1 -1
- package/dist/abort/signal.js +1 -1
- package/dist/ai/agent-context.d.mts +1 -1
- package/dist/ai/agent-context.js +3 -2
- package/dist/ai/backends.d.mts +3 -3
- package/dist/ai/backends.js +2 -2
- package/dist/ai/billing-context.d.mts +74 -0
- package/dist/ai/billing-context.js +129 -0
- package/dist/ai/credentials.d.mts +39 -5
- package/dist/ai/credentials.js +61 -6
- package/dist/ai/discover.d.mts +4 -0
- package/dist/ai/discover.js +4 -0
- package/dist/ai/exec.d.mts +1 -1
- package/dist/ai/exec.js +1 -1
- package/dist/ai/http.d.mts +8 -8
- package/dist/ai/http.js +6 -6
- package/dist/ai/profiles.d.mts +9 -10
- package/dist/ai/profiles.js +0 -5
- package/dist/ai/role.d.mts +58 -0
- package/dist/ai/role.js +96 -0
- package/dist/ai/route-heuristic.d.mts +177 -0
- package/dist/ai/route-heuristic.js +194 -0
- package/dist/ai/route.d.mts +31 -17
- package/dist/ai/route.js +35 -19
- package/dist/ai/spawn.d.mts +34 -1
- package/dist/ai/spawn.js +115 -3
- package/dist/ai/subagent-status.d.mts +2 -0
- package/dist/ai/subagent-status.js +2 -0
- package/dist/ai/tier.d.mts +1 -1
- package/dist/ai/types.d.mts +19 -2
- package/dist/ai/worktree.d.mts +1 -1
- package/dist/ai/worktree.js +3 -2
- package/dist/argv/parse.d.ts +2 -0
- package/dist/argv/parse.js +2 -0
- package/dist/bin/_internal.d.ts +1 -1
- package/dist/bin/_internal.js +1 -1
- package/dist/bin/prim.cjs +19253 -13937
- package/dist/bin/resolve.js +1 -1
- package/dist/bin/shadow.js +2 -1
- package/dist/bin/which.d.ts +28 -3
- package/dist/bin/which.js +45 -3
- package/dist/cacache/_internal.d.ts +10 -2
- package/dist/cacache/_internal.js +6 -10
- package/dist/cache/ttl/_internal.d.ts +33 -0
- package/dist/cache/ttl/_internal.js +68 -0
- package/dist/cache/ttl/browser.d.ts +56 -0
- package/dist/cache/ttl/browser.js +257 -0
- package/dist/cache/ttl/store.js +11 -34
- package/dist/cache/ttl/types.d.ts +46 -3
- package/dist/checks/primordials-defaults.d.ts +5 -5
- package/dist/checks/primordials-defaults.js +5 -5
- package/dist/checks/primordials.d.ts +1 -1
- package/dist/checks/primordials.js +25 -17
- package/dist/cli/check-primordials.d.ts +6 -1
- package/dist/cli/check-primordials.js +14 -5
- package/dist/cli/check.js +1 -1
- package/dist/cli/socket-lib.d.ts +1 -1
- package/dist/cli/socket-lib.js +3 -3
- package/dist/colors/socket-palette.d.ts +1 -1
- package/dist/compression/brotli.d.ts +6 -2
- package/dist/compression/brotli.js +5 -1
- package/dist/compression/gzip.d.ts +6 -2
- package/dist/compression/gzip.js +7 -2
- package/dist/config/layers.d.ts +53 -0
- package/dist/config/layers.js +83 -0
- package/dist/constants/agents.d.ts +3 -0
- package/dist/constants/agents.js +3 -0
- package/dist/constants/node.d.ts +14 -0
- package/dist/constants/node.js +14 -0
- package/dist/constants/package-default-node-range.js +1 -5
- package/dist/constants/packages.d.ts +5 -0
- package/dist/constants/packages.js +5 -0
- package/dist/constants/platform.d.ts +1 -1
- package/dist/constants/platform.js +1 -1
- package/dist/constants/socket.js +1 -1
- package/dist/constants/typescript.d.ts +5 -0
- package/dist/constants/typescript.js +5 -0
- package/dist/debug/_internal.d.ts +22 -7
- package/dist/debug/_internal.js +33 -15
- package/dist/debug/caller-info.js +1 -1
- package/dist/debug/namespace.js +11 -8
- package/dist/debug/output.d.ts +12 -1
- package/dist/debug/output.js +33 -16
- package/dist/dlx/binary-cache.js +1 -1
- package/dist/dlx/binary-resolution.js +8 -5
- package/dist/dlx/firewall.js +1 -1
- package/dist/dlx/lockfile.js +1 -1
- package/dist/eco/npm/npm/parse-lockfile.js +3 -2
- package/dist/eco/npm/vlt/exec.d.ts +1 -1
- package/dist/eco/npm/vlt/exec.js +1 -1
- package/dist/eco/npm/yarnpkg/yarn/parse-lockfile.js +1 -1
- package/dist/env/agents.d.ts +6 -0
- package/dist/env/agents.js +29 -0
- package/dist/env/flags.d.ts +12 -0
- package/dist/env/flags.js +23 -0
- package/dist/env/github-status.js +2 -2
- package/dist/env/providers.d.ts +6 -0
- package/dist/env/providers.js +23 -0
- package/dist/env/proxy.js +1 -1
- package/dist/env/rewire.d.ts +37 -3
- package/dist/env/rewire.js +60 -29
- package/dist/env/runtimes.d.ts +9 -0
- package/dist/env/runtimes.js +53 -0
- package/dist/env/socket-cli.d.ts +5 -2
- package/dist/env/socket-cli.js +6 -3
- package/dist/env/xdg.d.ts +17 -0
- package/dist/env/xdg.js +21 -1
- package/dist/errors/predicates.d.ts +3 -2
- package/dist/errors/predicates.js +5 -3
- package/dist/events/exit/_internal.d.ts +1 -23
- package/dist/external/@npmcli/package-json.js +3570 -4905
- package/dist/external/@npmcli/promise-spawn.js +2 -2
- package/dist/external/@sinclair/typebox/value.js +5 -4
- package/dist/external/@socketregistry/yocto-spinner.js +3 -3
- package/dist/external/@yarnpkg/extensions.js +1 -1
- package/dist/external/adm-zip.d.ts +82 -0
- package/dist/external/adm-zip.js +2 -2
- package/dist/external/cacache.d.ts +87 -0
- package/dist/external/debug.d.ts +22 -0
- package/dist/external/debug.js +11 -4
- package/dist/external/del.d.ts +1 -0
- package/dist/external/external-pack.d.ts +12 -0
- package/dist/external/external-pack.js +42 -35
- package/dist/external/fast-glob.d.ts +8 -0
- package/dist/external/fast-sort.d.ts +1 -0
- package/dist/external/get-east-asian-width.d.ts +5 -0
- package/dist/external/get-east-asian-width.js +8 -1
- package/dist/external/has-flag.d.ts +1 -0
- package/dist/external/inquirer-pack.d.ts +18 -0
- package/dist/external/libnpmexec.d.ts +35 -0
- package/dist/external/libnpmpack.d.ts +1 -0
- package/dist/external/make-fetch-happen.d.ts +13 -0
- package/dist/external/normalize-package-data.d.ts +4 -0
- package/dist/external/npm-core.d.ts +14 -0
- package/dist/external/npm-pack.d.ts +24 -0
- package/dist/external/npm-pack.js +28934 -31885
- package/dist/external/npm-package-arg.d.ts +4 -0
- package/dist/external/p-map.js +8 -1
- package/dist/external/pacote.d.ts +15 -0
- package/dist/external/pico-pack.d.ts +16 -0
- package/dist/external/pico-pack.js +38 -23
- package/dist/external/picomatch.d.ts +96 -0
- package/dist/external/pony-cause.d.ts +14 -0
- package/dist/external/semver.d.ts +60 -0
- package/dist/external/semver.js +1459 -4
- package/dist/external/shell-quote.d.ts +51 -0
- package/dist/external/shell-quote.js +55 -15
- package/dist/external/signal-exit.d.ts +1 -0
- package/dist/external/spdx-correct.d.ts +4 -0
- package/dist/external/spdx-expression-parse.d.ts +4 -0
- package/dist/external/spdx-pack.d.ts +10 -0
- package/dist/external/std-env.d.ts +284 -0
- package/dist/external/std-env.js +323 -0
- package/dist/external/streaming-iterables.d.ts +11 -0
- package/dist/external/supports-color.d.ts +1 -0
- package/dist/external/tar-fs.d.ts +31 -0
- package/dist/external/tar-fs.js +63 -16
- package/dist/external/validate-npm-package-name.d.ts +4 -0
- package/dist/external/which.d.ts +25 -0
- package/dist/external/which.js +2 -2
- package/dist/external/yargs-parser.d.ts +2 -0
- package/dist/external/yargs-parser.js +11 -3
- package/dist/external/yoctocolors-cjs.d.ts +51 -0
- package/dist/external-tools/bazel/asset-names.d.ts +1 -1
- package/dist/external-tools/bazel/from-download.d.ts +1 -1
- package/dist/external-tools/bazel/resolve.d.ts +3 -0
- package/dist/external-tools/bazel/resolve.js +3 -0
- package/dist/external-tools/cdxgen/asset-names.d.ts +5 -5
- package/dist/external-tools/cdxgen/asset-names.js +3 -3
- package/dist/external-tools/cdxgen/from-download.d.ts +2 -2
- package/dist/external-tools/cdxgen/from-download.js +1 -1
- package/dist/external-tools/cdxgen/resolve.d.ts +4 -1
- package/dist/external-tools/cdxgen/resolve.js +4 -1
- package/dist/external-tools/cdxgen/types.d.ts +1 -1
- package/dist/external-tools/from-download.d.ts +2 -2
- package/dist/external-tools/from-download.js +1 -1
- package/dist/external-tools/janus/asset-names.d.ts +4 -1
- package/dist/external-tools/janus/asset-names.js +3 -0
- package/dist/external-tools/janus/from-download.d.ts +3 -3
- package/dist/external-tools/janus/from-download.js +2 -2
- package/dist/external-tools/janus/resolve.d.ts +3 -0
- package/dist/external-tools/janus/resolve.js +3 -0
- package/dist/external-tools/jre/asset-names.d.ts +3 -1
- package/dist/external-tools/jre/asset-names.js +2 -0
- package/dist/external-tools/jre/detect-platform-arch.js +1 -1
- package/dist/external-tools/jre/from-download.d.ts +1 -1
- package/dist/external-tools/manifest.d.ts +5 -3
- package/dist/external-tools/manifest.js +5 -3
- package/dist/external-tools/opengrep/asset-names.d.ts +1 -1
- package/dist/external-tools/opengrep/resolve.d.ts +3 -0
- package/dist/external-tools/opengrep/resolve.js +3 -0
- package/dist/external-tools/python/asset-names.d.ts +3 -1
- package/dist/external-tools/python/asset-names.js +8 -4
- package/dist/external-tools/python/pin.js +3 -1
- package/dist/external-tools/python/resolve.d.ts +3 -0
- package/dist/external-tools/python/resolve.js +3 -0
- package/dist/external-tools/python/uv-install.d.ts +89 -0
- package/dist/external-tools/python/uv-install.js +165 -0
- package/dist/external-tools/sbt/resolve.d.ts +3 -0
- package/dist/external-tools/sbt/resolve.js +3 -0
- package/dist/external-tools/skillspector/from-uv.d.ts +30 -0
- package/dist/external-tools/skillspector/from-uv.js +56 -0
- package/dist/external-tools/skillspector/resolve.d.ts +18 -3
- package/dist/external-tools/skillspector/resolve.js +21 -8
- package/dist/external-tools/skillspector/types.d.ts +3 -1
- package/dist/external-tools/synp/resolve.d.ts +3 -0
- package/dist/external-tools/synp/resolve.js +3 -0
- package/dist/external-tools/trivy/asset-names.d.ts +1 -1
- package/dist/external-tools/trivy/resolve.d.ts +3 -0
- package/dist/external-tools/trivy/resolve.js +3 -0
- package/dist/external-tools/trufflehog/asset-names.d.ts +4 -1
- package/dist/external-tools/trufflehog/asset-names.js +3 -0
- package/dist/external-tools/trufflehog/from-download.d.ts +1 -1
- package/dist/external-tools/trufflehog/resolve.d.ts +3 -0
- package/dist/external-tools/trufflehog/resolve.js +3 -0
- package/dist/external-tools/uv/asset-names.d.ts +36 -0
- package/dist/external-tools/uv/asset-names.js +73 -0
- package/dist/external-tools/uv/from-download.d.ts +17 -0
- package/dist/external-tools/uv/from-download.js +50 -0
- package/dist/external-tools/uv/from-path.d.ts +5 -0
- package/dist/external-tools/uv/from-path.js +22 -0
- package/dist/external-tools/uv/from-vfs.d.ts +7 -0
- package/dist/external-tools/uv/from-vfs.js +26 -0
- package/dist/external-tools/uv/resolve.d.ts +28 -0
- package/dist/external-tools/uv/resolve.js +64 -0
- package/dist/external-tools/uv/types.d.ts +24 -0
- package/dist/external-tools/uv/types.js +2 -0
- package/dist/fleet/repo-config.d.ts +55 -0
- package/dist/fleet/repo-config.js +81 -0
- package/dist/fs/_internal.d.ts +1 -1
- package/dist/fs/_internal.js +1 -1
- package/dist/fs/access.d.ts +2 -0
- package/dist/fs/access.js +2 -0
- package/dist/fs/copy.d.ts +88 -0
- package/dist/fs/copy.js +89 -0
- package/dist/fs/find.js +1 -2
- package/dist/fs/inspect.d.ts +2 -2
- package/dist/fs/read-file.js +3 -4
- package/dist/fs/safe.js +2 -2
- package/dist/git/_internal.js +7 -3
- package/dist/github/commit.d.ts +92 -0
- package/dist/github/commit.js +113 -0
- package/dist/github/ghsa.js +1 -1
- package/dist/github/refs-graphql.js +1 -1
- package/dist/github/refs.js +10 -15
- package/dist/github/request.js +1 -1
- package/dist/github/token.d.ts +5 -2
- package/dist/github/token.js +6 -4
- package/dist/github/workflow-runs.d.ts +107 -0
- package/dist/github/workflow-runs.js +98 -0
- package/dist/globs/_internal.js +1 -1
- package/dist/http-request/_internal.d.ts +1 -1
- package/dist/http-request/browser.d.ts +6 -0
- package/dist/http-request/browser.js +4 -3
- package/dist/http-request/checksum-file.js +1 -1
- package/dist/http-request/download.js +2 -0
- package/dist/http-request/headers.d.ts +1 -1
- package/dist/http-request/headers.js +2 -2
- package/dist/http-request/request-attempt.js +6 -3
- package/dist/http-request/request-types.d.ts +10 -1
- package/dist/http-request/request.js +2 -2
- package/dist/http-request/user-agent.d.ts +23 -2
- package/dist/http-request/user-agent.js +48 -6
- package/dist/integrity.d.ts +127 -78
- package/dist/integrity.js +170 -84
- package/dist/json/format.js +4 -1
- package/dist/logger/_internal.d.ts +13 -15
- package/dist/logger/_internal.js +21 -21
- package/dist/logger/colors.d.ts +10 -5
- package/dist/logger/colors.js +7 -14
- package/dist/logger/console-methods.js +2 -2
- package/dist/logger/console.d.ts +1 -0
- package/dist/logger/console.js +9 -9
- package/dist/logger/node.js +2 -1
- package/dist/logger/symbols-builder.js +7 -8
- package/dist/logger/symbols.js +8 -8
- package/dist/native-messaging/install.js +1 -1
- package/dist/native-messaging/rate-limit.d.ts +4 -1
- package/dist/native-messaging/rate-limit.js +4 -1
- package/dist/node/events.d.ts +3 -0
- package/dist/node/events.js +3 -0
- package/dist/node/fs.d.ts +1 -1
- package/dist/node/module.d.ts +73 -2
- package/dist/node/module.js +97 -12
- package/dist/node/timers-promises.d.ts +3 -0
- package/dist/node/timers-promises.js +3 -0
- package/dist/node/url.d.ts +3 -0
- package/dist/node/url.js +3 -0
- package/dist/npm/meta-cache.d.ts +183 -0
- package/dist/npm/meta-cache.js +318 -0
- package/dist/npm/meta-slice.d.ts +27 -0
- package/dist/npm/meta-slice.js +68 -0
- package/dist/npm/meta-types.d.ts +282 -0
- package/dist/npm/meta-types.js +2 -0
- package/dist/npm/meta.d.ts +125 -0
- package/dist/npm/meta.js +347 -0
- package/dist/npm/registry.d.ts +212 -0
- package/dist/npm/registry.js +284 -0
- package/dist/objects/getters.d.ts +1 -1
- package/dist/objects/getters.js +1 -1
- package/dist/objects/predicates.js +1 -1
- package/dist/packages/exports.js +2 -2
- package/dist/packages/isolation.js +1 -1
- package/dist/packages/manifest.d.ts +29 -0
- package/dist/packages/manifest.js +44 -9
- package/dist/packages/metadata-extensions.js +2 -4
- package/dist/packages/normalize.js +1 -1
- package/dist/packages/provenance.d.ts +8 -0
- package/dist/packages/provenance.js +10 -2
- package/dist/packages/specs.js +1 -1
- package/dist/packages/tarball.js +1 -2
- package/dist/packages/validation.d.ts +0 -10
- package/dist/packages/validation.js +0 -14
- package/dist/paths/_internal.d.ts +1 -7
- package/dist/paths/_internal.js +9 -15
- package/dist/paths/conversion.js +1 -1
- package/dist/paths/exts.d.ts +30 -0
- package/dist/paths/exts.js +30 -0
- package/dist/paths/filenames.d.ts +6 -0
- package/dist/paths/filenames.js +6 -0
- package/dist/paths/globs.d.ts +6 -0
- package/dist/paths/globs.js +6 -0
- package/dist/paths/normalize.js +1 -1
- package/dist/paths/predicates.js +2 -1
- package/dist/paths/resolve.js +19 -14
- package/dist/paths/socket.d.ts +81 -30
- package/dist/paths/socket.js +102 -28
- package/dist/perf/metrics.js +1 -1
- package/dist/perf/report.js +5 -3
- package/dist/pkg-ext/data.js +0 -2
- package/dist/primordials/globals.d.ts +1 -1
- package/dist/primordials/globals.js +1 -1
- package/dist/primordials/headers.d.ts +13 -1
- package/dist/primordials/headers.js +13 -1
- package/dist/primordials/process.d.ts +1 -1
- package/dist/primordials/process.js +1 -1
- package/dist/primordials/url.d.ts +18 -0
- package/dist/primordials/url.js +18 -0
- package/dist/process/spawn/child.js +3 -5
- package/dist/promises/_internal.d.ts +1 -1
- package/dist/promises/_internal.js +1 -2
- package/dist/promises/options.js +3 -3
- package/dist/regexps/spec.js +1 -1
- package/dist/releases/socket-btm-binary-naming.js +12 -1
- package/dist/schema/validate.js +1 -1
- package/dist/secrets/_internal.d.ts +1 -1
- package/dist/secrets/_internal.js +1 -1
- package/dist/secrets/broker.d.ts +35 -0
- package/dist/secrets/broker.js +72 -0
- package/dist/secrets/find.d.ts +8 -6
- package/dist/secrets/find.js +17 -3
- package/dist/secrets/keychain.d.ts +10 -1
- package/dist/secrets/keychain.js +10 -1
- package/dist/secrets/rc.js +1 -1
- package/dist/secrets/socket-api-token.d.ts +1 -1
- package/dist/secrets/socket-api-token.js +1 -1
- package/dist/secrets/types.d.ts +1 -1
- package/dist/smol/detect.js +1 -1
- package/dist/smol/http.d.ts +2 -0
- package/dist/smol/http.js +3 -1
- package/dist/smol/https.d.ts +2 -0
- package/dist/smol/https.js +3 -1
- package/dist/smol/manifest.js +1 -1
- package/dist/smol/path.js +1 -1
- package/dist/smol/primordial.js +1 -1
- package/dist/smol/purl.js +1 -1
- package/dist/smol/versions.js +1 -1
- package/dist/smol/vfs.js +1 -1
- package/dist/sorts/_internal.d.ts +2 -4
- package/dist/sorts/_internal.js +1 -7
- package/dist/sorts/semver.js +2 -2
- package/dist/spinner/create-spinner-class.js +1 -1
- package/dist/spinner/format.js +2 -4
- package/dist/stdio/footer.js +8 -7
- package/dist/stdio/progress.js +1 -1
- package/dist/stdio/prompts.d.ts +8 -23
- package/dist/stdio/prompts.js +28 -52
- package/dist/strings/format.js +1 -1
- package/dist/strings/predicates.d.ts +2 -2
- package/dist/strings/search.js +2 -2
- package/dist/strings/types.d.ts +4 -0
- package/dist/strings/width.d.ts +1 -0
- package/dist/strings/width.js +17 -8
- package/dist/themes/context.d.ts +18 -3
- package/dist/themes/context.js +28 -14
- package/dist/versions/_internal.d.ts +43 -13
- package/dist/versions/_internal.js +27 -15
- package/dist/versions/compare.d.ts +16 -10
- package/dist/versions/compare.js +36 -16
- package/dist/versions/parse.js +1 -1
- package/dist/versions/range.js +3 -2
- package/dist/words/pluralize.js +4 -1
- package/llms.txt +63 -0
- package/package.json +271 -40
package/dist/ai/http.js
CHANGED
|
@@ -12,7 +12,7 @@ const require_http_request_node = require('../http-request/node.js');
|
|
|
12
12
|
* (`api.fireworks.ai`) and Synthetic (`api.synthetic.new`). The CLI path
|
|
13
13
|
* (`spawn.mts`) drives an interactive agent binary; this path is for a
|
|
14
14
|
* script/hook that needs a single completion from a model without an agent
|
|
15
|
-
* harness (the way the local OpenCode setup reaches GLM-5.
|
|
15
|
+
* harness (the way the local OpenCode setup reaches GLM-5.2 / Kimi-K2.6). Why
|
|
16
16
|
* a separate module from `spawn.mts`: those are different surfaces. A CLI
|
|
17
17
|
* agent gets tools + a permission mode + a working dir; an HTTP completion
|
|
18
18
|
* gets a prompt + a model + (optionally) a reasoning effort and returns text.
|
|
@@ -21,10 +21,10 @@ const require_http_request_node = require('../http-request/node.js');
|
|
|
21
21
|
* function-calling surface — they're plain completions, so there's no agentic
|
|
22
22
|
* capability to constrain. The token is read from the env var the provider
|
|
23
23
|
* config names (`FIREWORKS_API_KEY` / `SYNTHETIC_API_KEY`), NEVER passed
|
|
24
|
-
* inline, and never logged — same token-hygiene rule as the rest of
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
24
|
+
* inline, and never logged — same token-hygiene rule as the rest of Socket. A
|
|
25
|
+
* missing token throws with the exact env var to set. Wire format is the
|
|
26
|
+
* OpenAI Chat Completions API (`POST {baseUrl}/chat/completions`), which both
|
|
27
|
+
* providers implement.
|
|
28
28
|
*/
|
|
29
29
|
/**
|
|
30
30
|
* Built-in OpenAI-compatible providers. Add an entry to support a new one — no
|
|
@@ -81,7 +81,7 @@ function buildChatRequestBody(options) {
|
|
|
81
81
|
* ;```ts
|
|
82
82
|
* const { text } = await callAiHttpModel({
|
|
83
83
|
* provider: 'fireworks',
|
|
84
|
-
* model: 'accounts/fireworks/models/glm-
|
|
84
|
+
* model: 'accounts/fireworks/models/glm-5p2',
|
|
85
85
|
* prompt: 'Summarize this diff: …',
|
|
86
86
|
* effort: 'high',
|
|
87
87
|
* })
|
package/dist/ai/profiles.d.mts
CHANGED
|
@@ -11,11 +11,10 @@
|
|
|
11
11
|
* WebSearch. No Edit, no Write, no Bash. Static-analysis skills
|
|
12
12
|
* (scanning-quality, scanning-security).
|
|
13
13
|
* - `AI_PROFILE.edit` — in-place edits only. Read + Edit + Grep + Glob. NO
|
|
14
|
-
* Write (can't create files), NO
|
|
15
|
-
*
|
|
16
|
-
* - `AI_PROFILE.create` — edit AND create files. Adds
|
|
17
|
-
*
|
|
18
|
-
* modules.
|
|
14
|
+
* Write (can't create files), NO Bash. Lint autofix / codemods constrained
|
|
15
|
+
* to existing files.
|
|
16
|
+
* - `AI_PROFILE.create` — edit AND create files. Adds Write on top of `.edit`.
|
|
17
|
+
* Still no Bash. Codegen, adding a test, refactors that split modules.
|
|
19
18
|
* - `AI_PROFILE.verify` — `.create` plus a READ-ONLY Bash allowlist (node /
|
|
20
19
|
* pnpm test+run / git status·diff·log). Lets an agent author files AND run
|
|
21
20
|
* the verifier (its own tests, a check script) — but it CANNOT mutate the
|
|
@@ -66,13 +65,13 @@ export declare const BASH_ALLOW: {
|
|
|
66
65
|
export declare const AI_PROFILE: {
|
|
67
66
|
readonly read: {
|
|
68
67
|
readonly allow: readonly [];
|
|
69
|
-
readonly disallow: readonly ["Agent", "Bash", "Edit", "
|
|
68
|
+
readonly disallow: readonly ["Agent", "Bash", "Edit", "Write"];
|
|
70
69
|
readonly permissionMode: 'dontAsk';
|
|
71
70
|
readonly tools: readonly ["Glob", "Grep", "Read", "WebFetch", "WebSearch"];
|
|
72
71
|
};
|
|
73
72
|
readonly edit: {
|
|
74
73
|
readonly allow: readonly [];
|
|
75
|
-
readonly disallow: readonly ["Agent", "Bash", "
|
|
74
|
+
readonly disallow: readonly ["Agent", "Bash", "WebFetch", "WebSearch", "Write"];
|
|
76
75
|
readonly permissionMode: 'acceptEdits';
|
|
77
76
|
readonly tools: readonly ["Edit", "Glob", "Grep", "Read"];
|
|
78
77
|
};
|
|
@@ -80,18 +79,18 @@ export declare const AI_PROFILE: {
|
|
|
80
79
|
readonly allow: readonly [];
|
|
81
80
|
readonly disallow: readonly ["Agent", "Bash", "WebFetch", "WebSearch"];
|
|
82
81
|
readonly permissionMode: 'acceptEdits';
|
|
83
|
-
readonly tools: readonly ["Edit", "Glob", "Grep", "
|
|
82
|
+
readonly tools: readonly ["Edit", "Glob", "Grep", "Read", "Write"];
|
|
84
83
|
};
|
|
85
84
|
readonly verify: {
|
|
86
85
|
readonly allow: readonly ["Bash(git status:*)", "Bash(git diff:*)", "Bash(git log:*)", "Bash(node:*)", "Bash(pnpm run:*)", "Bash(pnpm test:*)"];
|
|
87
86
|
readonly disallow: readonly ["Agent", "WebFetch", "WebSearch"];
|
|
88
87
|
readonly permissionMode: 'acceptEdits';
|
|
89
|
-
readonly tools: readonly ["Bash", "Edit", "Glob", "Grep", "
|
|
88
|
+
readonly tools: readonly ["Bash", "Edit", "Glob", "Grep", "Read", "Write"];
|
|
90
89
|
};
|
|
91
90
|
readonly full: {
|
|
92
91
|
readonly allow: readonly ["Bash(git status:*)", "Bash(git diff:*)", "Bash(git log:*)", "Bash(node:*)", "Bash(pnpm run:*)", "Bash(pnpm test:*)", "Bash(git add:*)", "Bash(git commit:*)", "Bash(pnpm exec:*)"];
|
|
93
92
|
readonly disallow: readonly ["Agent", "WebFetch", "WebSearch"];
|
|
94
93
|
readonly permissionMode: 'acceptEdits';
|
|
95
|
-
readonly tools: readonly ["Bash", "Edit", "Glob", "Grep", "
|
|
94
|
+
readonly tools: readonly ["Bash", "Edit", "Glob", "Grep", "Read", "Write"];
|
|
96
95
|
};
|
|
97
96
|
};
|
package/dist/ai/profiles.js
CHANGED
|
@@ -44,7 +44,6 @@ const AI_PROFILE = {
|
|
|
44
44
|
"Agent",
|
|
45
45
|
"Bash",
|
|
46
46
|
"Edit",
|
|
47
|
-
"MultiEdit",
|
|
48
47
|
"Write"
|
|
49
48
|
],
|
|
50
49
|
permissionMode: "dontAsk",
|
|
@@ -61,7 +60,6 @@ const AI_PROFILE = {
|
|
|
61
60
|
disallow: [
|
|
62
61
|
"Agent",
|
|
63
62
|
"Bash",
|
|
64
|
-
"MultiEdit",
|
|
65
63
|
"WebFetch",
|
|
66
64
|
"WebSearch",
|
|
67
65
|
"Write"
|
|
@@ -87,7 +85,6 @@ const AI_PROFILE = {
|
|
|
87
85
|
"Edit",
|
|
88
86
|
"Glob",
|
|
89
87
|
"Grep",
|
|
90
|
-
"MultiEdit",
|
|
91
88
|
"Read",
|
|
92
89
|
"Write"
|
|
93
90
|
]
|
|
@@ -105,7 +102,6 @@ const AI_PROFILE = {
|
|
|
105
102
|
"Edit",
|
|
106
103
|
"Glob",
|
|
107
104
|
"Grep",
|
|
108
|
-
"MultiEdit",
|
|
109
105
|
"Read",
|
|
110
106
|
"Write"
|
|
111
107
|
]
|
|
@@ -127,7 +123,6 @@ const AI_PROFILE = {
|
|
|
127
123
|
"Edit",
|
|
128
124
|
"Glob",
|
|
129
125
|
"Grep",
|
|
130
|
-
"MultiEdit",
|
|
131
126
|
"Read",
|
|
132
127
|
"Write"
|
|
133
128
|
]
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Declarative ROLE → (tier, profile) orchestration for AI call-outs. A
|
|
3
|
+
* caller names the ROLE its spawn plays — discovery, execution, planning,
|
|
4
|
+
* review, verification — and gets the fleet-policy (model, effort) pair via
|
|
5
|
+
* `AI_TIER` plus the matching permission `AI_PROFILE`, instead of hardcoding
|
|
6
|
+
* a model string and hand-pairing a profile at every site.
|
|
7
|
+
* The policy encodes fleet doctrine (see docs/agents.md/fleet/{token-spend,
|
|
8
|
+
* delegating-execution,fable-fallback}.md): Fable is the planning/review
|
|
9
|
+
* brain; execution + verification run on the sonnet floor to save tokens
|
|
10
|
+
* (mechanical execution drops to haiku); Opus is reserved for
|
|
11
|
+
* security-sensitive planning/review — never Fable there.
|
|
12
|
+
* Everything downstream is reuse: `spawnForRole` delegates to
|
|
13
|
+
* `spawnTierWithFallback`, so the model/effort table (`AI_TIER`), the
|
|
14
|
+
* availability-gated cross-engine fallback (`route.mts`), and the
|
|
15
|
+
* Fable-adaptive-only effort omission (`spawn.mts`) stay the single source.
|
|
16
|
+
* Model + effort can never be mismatched or omitted here — the tier supplies
|
|
17
|
+
* both, and the profile supplies tools/permission, so a caller cannot drift
|
|
18
|
+
* them apart.
|
|
19
|
+
*/
|
|
20
|
+
import { AI_PROFILE } from './profiles.mts';
|
|
21
|
+
import type { RouteContext } from './route.mts';
|
|
22
|
+
import type { TierSpawnResult } from './spawn.mts';
|
|
23
|
+
import type { AiTier } from './tier.mts';
|
|
24
|
+
import type { SpawnAiAgentOptions } from './types.mts';
|
|
25
|
+
export type AiRole = 'discovery' | 'execution' | 'planning' | 'review' | 'verification';
|
|
26
|
+
export type RoleSensitivity = 'benign' | 'security';
|
|
27
|
+
export interface RoleTierLevers {
|
|
28
|
+
readonly mechanical?: boolean | undefined;
|
|
29
|
+
readonly sensitivity?: RoleSensitivity | undefined;
|
|
30
|
+
}
|
|
31
|
+
export interface RolePolicy {
|
|
32
|
+
readonly tier: AiTier;
|
|
33
|
+
readonly securityTier?: AiTier | undefined;
|
|
34
|
+
readonly profile: keyof typeof AI_PROFILE;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* The role → policy table. The one place a role's tier + permission profile
|
|
38
|
+
* live; consumers derive, never re-encode.
|
|
39
|
+
*/
|
|
40
|
+
export declare const ROLE_POLICY: Readonly<Record<AiRole, RolePolicy>>;
|
|
41
|
+
/**
|
|
42
|
+
* Resolve the tier a role runs at, applying the two levers: `security`
|
|
43
|
+
* sensitivity escalates to the role's `securityTier` (planning/review → opus),
|
|
44
|
+
* and `mechanical` execution drops to the haiku floor. Pure — no I/O.
|
|
45
|
+
*/
|
|
46
|
+
export declare function resolveRoleTier(role: AiRole, options?: RoleTierLevers | undefined): AiTier;
|
|
47
|
+
export interface SpawnForRoleOptions extends Omit<SpawnAiAgentOptions, 'agent' | 'allow' | 'disallow' | 'effort' | 'model' | 'permissionMode' | 'tools'> {
|
|
48
|
+
readonly sensitivity?: RoleSensitivity | undefined;
|
|
49
|
+
readonly mechanical?: boolean | undefined;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Spawn an AI call-out by the ROLE it plays. Resolves role → tier (via
|
|
53
|
+
* `resolveRoleTier`) and role → permission profile (via `AI_PROFILE`), then
|
|
54
|
+
* delegates to `spawnTierWithFallback` so model/effort/fallback/Fable handling
|
|
55
|
+
* stay in the canonical tier layer. The caller supplies only prompt/cwd/etc —
|
|
56
|
+
* never a model, effort, or profile.
|
|
57
|
+
*/
|
|
58
|
+
export declare function spawnForRole(role: AiRole, ctx: RouteContext, options: SpawnForRoleOptions): Promise<TierSpawnResult>;
|
package/dist/ai/role.js
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/* Socket Lib - Built with rolldown */
|
|
3
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
4
|
+
const require_ai_spawn = require('./spawn.js');
|
|
5
|
+
const require_ai_profiles = require('./profiles.js');
|
|
6
|
+
|
|
7
|
+
//#region src/ai/role.mts
|
|
8
|
+
/**
|
|
9
|
+
* @file Declarative ROLE → (tier, profile) orchestration for AI call-outs. A
|
|
10
|
+
* caller names the ROLE its spawn plays — discovery, execution, planning,
|
|
11
|
+
* review, verification — and gets the fleet-policy (model, effort) pair via
|
|
12
|
+
* `AI_TIER` plus the matching permission `AI_PROFILE`, instead of hardcoding
|
|
13
|
+
* a model string and hand-pairing a profile at every site.
|
|
14
|
+
* The policy encodes fleet doctrine (see docs/agents.md/fleet/{token-spend,
|
|
15
|
+
* delegating-execution,fable-fallback}.md): Fable is the planning/review
|
|
16
|
+
* brain; execution + verification run on the sonnet floor to save tokens
|
|
17
|
+
* (mechanical execution drops to haiku); Opus is reserved for
|
|
18
|
+
* security-sensitive planning/review — never Fable there.
|
|
19
|
+
* Everything downstream is reuse: `spawnForRole` delegates to
|
|
20
|
+
* `spawnTierWithFallback`, so the model/effort table (`AI_TIER`), the
|
|
21
|
+
* availability-gated cross-engine fallback (`route.mts`), and the
|
|
22
|
+
* Fable-adaptive-only effort omission (`spawn.mts`) stay the single source.
|
|
23
|
+
* Model + effort can never be mismatched or omitted here — the tier supplies
|
|
24
|
+
* both, and the profile supplies tools/permission, so a caller cannot drift
|
|
25
|
+
* them apart.
|
|
26
|
+
*/
|
|
27
|
+
/**
|
|
28
|
+
* The role → policy table. The one place a role's tier + permission profile
|
|
29
|
+
* live; consumers derive, never re-encode.
|
|
30
|
+
*/
|
|
31
|
+
const ROLE_POLICY = {
|
|
32
|
+
discovery: {
|
|
33
|
+
profile: "read",
|
|
34
|
+
tier: "sonnet"
|
|
35
|
+
},
|
|
36
|
+
execution: {
|
|
37
|
+
profile: "verify",
|
|
38
|
+
tier: "sonnet"
|
|
39
|
+
},
|
|
40
|
+
planning: {
|
|
41
|
+
profile: "read",
|
|
42
|
+
securityTier: "opus",
|
|
43
|
+
tier: "fable"
|
|
44
|
+
},
|
|
45
|
+
review: {
|
|
46
|
+
profile: "read",
|
|
47
|
+
securityTier: "opus",
|
|
48
|
+
tier: "fable"
|
|
49
|
+
},
|
|
50
|
+
verification: {
|
|
51
|
+
profile: "verify",
|
|
52
|
+
tier: "sonnet"
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* Resolve the tier a role runs at, applying the two levers: `security`
|
|
57
|
+
* sensitivity escalates to the role's `securityTier` (planning/review → opus),
|
|
58
|
+
* and `mechanical` execution drops to the haiku floor. Pure — no I/O.
|
|
59
|
+
*/
|
|
60
|
+
function resolveRoleTier(role, options) {
|
|
61
|
+
const opts = {
|
|
62
|
+
__proto__: null,
|
|
63
|
+
...options
|
|
64
|
+
};
|
|
65
|
+
const policy = ROLE_POLICY[role];
|
|
66
|
+
if (opts.mechanical && role === "execution") return "haiku";
|
|
67
|
+
if (opts.sensitivity === "security" && policy.securityTier !== void 0) return policy.securityTier;
|
|
68
|
+
return policy.tier;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Spawn an AI call-out by the ROLE it plays. Resolves role → tier (via
|
|
72
|
+
* `resolveRoleTier`) and role → permission profile (via `AI_PROFILE`), then
|
|
73
|
+
* delegates to `spawnTierWithFallback` so model/effort/fallback/Fable handling
|
|
74
|
+
* stay in the canonical tier layer. The caller supplies only prompt/cwd/etc —
|
|
75
|
+
* never a model, effort, or profile.
|
|
76
|
+
*/
|
|
77
|
+
function spawnForRole(role, ctx, options) {
|
|
78
|
+
const { mechanical, sensitivity, ...rest } = {
|
|
79
|
+
__proto__: null,
|
|
80
|
+
...options
|
|
81
|
+
};
|
|
82
|
+
const tier = resolveRoleTier(role, {
|
|
83
|
+
mechanical,
|
|
84
|
+
sensitivity
|
|
85
|
+
});
|
|
86
|
+
const profile = require_ai_profiles.AI_PROFILE[ROLE_POLICY[role].profile];
|
|
87
|
+
return require_ai_spawn.spawnTierWithFallback(tier, ctx, {
|
|
88
|
+
...profile,
|
|
89
|
+
...rest
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
//#endregion
|
|
94
|
+
exports.ROLE_POLICY = ROLE_POLICY;
|
|
95
|
+
exports.resolveRoleTier = resolveRoleTier;
|
|
96
|
+
exports.spawnForRole = spawnForRole;
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Billing-aware routing heuristic — a PURE policy layer over `route.mts`.
|
|
3
|
+
* `route.mts` answers "which cross-engine candidates for this tier are
|
|
4
|
+
* installed + keyed, in static preference order"; this module answers "given
|
|
5
|
+
* how each provider is BILLED (a subscription seat vs a flat-rate plan vs
|
|
6
|
+
* metered dollars), how much budget headroom remains, and whether we're in
|
|
7
|
+
* local dev or a locked-down CI — REORDER those candidates so the cheapest
|
|
8
|
+
* ration that still meets the tier's quality bar runs first." It is pure (no
|
|
9
|
+
* I/O): a caller fans out the billing / headroom probes once (the discovery
|
|
10
|
+
* layer) and passes a `BillingContext` in, exactly as `route.mts` takes a
|
|
11
|
+
* probed `RouteContext`. The candidates within a tier chain are cross-engine
|
|
12
|
+
* EQUIVALENTS at that capability level, so reordering them by cost is safe —
|
|
13
|
+
* the tier already fixed the quality bar. NO per-user constants live here.
|
|
14
|
+
* Every dollar limit, plan tier, member count, and promo window is DATA on
|
|
15
|
+
* the passed-in context; this file is formula + ordering only, so the same
|
|
16
|
+
* policy serves a metered org with a big budget, a free-promo subscription
|
|
17
|
+
* seat, a shared team pool, or a member with no credentials at all. Even
|
|
18
|
+
* "which model is suspended" is not encoded here — that is the
|
|
19
|
+
* route/availability layer's concern. Two design choices keep it a "sweet
|
|
20
|
+
* spot" rather than a blunt cost-sort: high-value tiers (opus/fable) stay
|
|
21
|
+
* QUALITY-FIRST (the Claude head leads) and only DEMOTE an account under
|
|
22
|
+
* budget pressure, while commodity tiers (haiku/sonnet) in local dev PROMOTE
|
|
23
|
+
* the cheapest equivalent to preserve the metered budget for work that needs
|
|
24
|
+
* it; and CI keeps the locked static order so a headless run never reorders
|
|
25
|
+
* away from its single available provider.
|
|
26
|
+
*/
|
|
27
|
+
import type { CredentialProvider } from './credentials.mts';
|
|
28
|
+
import type { RouteContext, TierCandidate } from './route.mts';
|
|
29
|
+
import type { AiTier } from './tier.mts';
|
|
30
|
+
/**
|
|
31
|
+
* How a provider's credential is billed, which decides what the marginal token
|
|
32
|
+
* actually costs:
|
|
33
|
+
*
|
|
34
|
+
* - `flat-rate` — a fixed monthly plan with a usage window (e.g. N requests per
|
|
35
|
+
* 5h). Marginal cost is $0 while the window has room.
|
|
36
|
+
* - `metered` — pay per token against a (usually large, readable) monthly spend
|
|
37
|
+
* limit. Marginal cost is real dollars.
|
|
38
|
+
* - `subscription` — a seat (Claude Max, ChatGPT Pro) with an opaque weekly
|
|
39
|
+
* quota. Marginal cost is $0 until the quota is hit, then it stops.
|
|
40
|
+
*/
|
|
41
|
+
export type BillingKind = 'flat-rate' | 'metered' | 'subscription';
|
|
42
|
+
/**
|
|
43
|
+
* Where routing is running. `local` dev has the full discovered provider set
|
|
44
|
+
* and may chase the cheapest equivalent; `ci` is locked to the secrets actually
|
|
45
|
+
* present (often a single provider) under the four-flag lockdown, so the policy
|
|
46
|
+
* keeps the static order and never reorders away from the one available lane.
|
|
47
|
+
*/
|
|
48
|
+
export type RoutingEnv = 'ci' | 'local';
|
|
49
|
+
/**
|
|
50
|
+
* The shape of a unit of work, mapped to a capability tier by
|
|
51
|
+
* `taskClassToTier`. Orthogonal to billing: the class fixes the quality bar,
|
|
52
|
+
* billing decides which equivalent at that bar is cheapest.
|
|
53
|
+
*/
|
|
54
|
+
export type TaskClass = 'agentic' | 'code' | 'grunt' | 'plan';
|
|
55
|
+
/**
|
|
56
|
+
* Remaining-headroom signal for one account, as read by the discovery layer
|
|
57
|
+
* from the provider's live API (metered: spend ÷ limit; flat-rate: window used
|
|
58
|
+
* ÷ window limit). `fraction` is remaining headroom in [0, 1] (1 = full, 0 =
|
|
59
|
+
* none), or `undefined` when no signal is available — a subscription seat with
|
|
60
|
+
* no programmatic quota read, which the policy then treats reactively.
|
|
61
|
+
* `exhausted` is the hard stop: a cap was hit or a 429 was observed, so the
|
|
62
|
+
* account should fall to the back of the order regardless of `fraction`.
|
|
63
|
+
*/
|
|
64
|
+
export interface BillingHeadroom {
|
|
65
|
+
readonly exhausted: boolean;
|
|
66
|
+
readonly fraction: number | undefined;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* One provider's billing situation for the credential that will actually be
|
|
70
|
+
* used (the resolver yields one token per provider, so one account per provider
|
|
71
|
+
* is the routing-relevant view). Multi-account-per-provider accounting belongs
|
|
72
|
+
* to the budget layer, not the candidate order.
|
|
73
|
+
*/
|
|
74
|
+
export interface BillingAccount {
|
|
75
|
+
readonly headroom?: BillingHeadroom | undefined;
|
|
76
|
+
readonly kind: BillingKind;
|
|
77
|
+
readonly prefer?: number | undefined;
|
|
78
|
+
readonly provider: CredentialProvider;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* The per-provider billing view a caller probes once and passes in — the
|
|
82
|
+
* billing analog of `RouteContext`. Keyed by provider; a provider absent from
|
|
83
|
+
* the map has no known billing signal and is left in static order.
|
|
84
|
+
*/
|
|
85
|
+
export type BillingContext = Readonly<Partial<Record<CredentialProvider, BillingAccount>>>;
|
|
86
|
+
/**
|
|
87
|
+
* Canonical task-class → tier. The class fixes the capability bar; the tier
|
|
88
|
+
* chain then offers cross-engine equivalents at that bar for billing to
|
|
89
|
+
* reorder.
|
|
90
|
+
*
|
|
91
|
+
* - `grunt` → `haiku` — classify / summarize / single-token rewrites.
|
|
92
|
+
* - `code` → `sonnet` — control-flow / caller-chain edits, feature work.
|
|
93
|
+
* - `agentic` → `opus` — long tool-use loops, high-value autonomous work.
|
|
94
|
+
* - `plan` → `opus` — decomposition / architecture (escalate to `fable` only
|
|
95
|
+
* explicitly, never by default — and only when it is not suspended).
|
|
96
|
+
*/
|
|
97
|
+
export declare const TASK_CLASS_TIER: Readonly<Record<TaskClass, AiTier>>;
|
|
98
|
+
/**
|
|
99
|
+
* Marginal-cost rank by billing kind, cheapest ration first (lower =
|
|
100
|
+
* preferred). Used only for commodity tiers in local dev — high-value tiers
|
|
101
|
+
* stay quality-first. Flat-rate and subscription are both $0-until-cap;
|
|
102
|
+
* flat-rate leads because its window resets fast (hours) vs a subscription's
|
|
103
|
+
* weekly cap.
|
|
104
|
+
*/
|
|
105
|
+
export declare const COST_RANK: Readonly<Record<BillingKind, number>>;
|
|
106
|
+
/**
|
|
107
|
+
* Default per-task-class budget weights for `allocateBudget`. Reserves more of
|
|
108
|
+
* a member's share for high-value work (plan/agentic) than for bulk
|
|
109
|
+
* (grunt/code). Overridable per call — these are sane defaults, not per-user
|
|
110
|
+
* values.
|
|
111
|
+
*/
|
|
112
|
+
export declare const DEFAULT_TASK_CLASS_WEIGHTS: Readonly<Record<TaskClass, number>>;
|
|
113
|
+
/**
|
|
114
|
+
* Headroom fraction at or below which a metered/flat-rate account is demoted
|
|
115
|
+
* (predictive backoff before the hard cap). A config knob with a sane default;
|
|
116
|
+
* callers override per `orderCandidates` call.
|
|
117
|
+
*/
|
|
118
|
+
export declare const DEFAULT_DEMOTE_THRESHOLD = 0.2;
|
|
119
|
+
/**
|
|
120
|
+
* Per-task-class dollar caps. A generic allocation, not a per-user table —
|
|
121
|
+
* computed from a total + member count + weights, all of which are inputs.
|
|
122
|
+
*/
|
|
123
|
+
export type BudgetAllocation = Readonly<Record<TaskClass, number>>;
|
|
124
|
+
export interface BudgetAllocationOptions {
|
|
125
|
+
readonly totalUsd: number;
|
|
126
|
+
readonly members?: number | undefined;
|
|
127
|
+
readonly weights?: Readonly<Partial<Record<TaskClass, number>>> | undefined;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Turn a total budget into reasonable per-member, per-task-class caps by a
|
|
131
|
+
* generic formula: split the total evenly across members, then distribute each
|
|
132
|
+
* member's share across task classes proportional to their weights. The numbers
|
|
133
|
+
* in are private; the formula is generic and committed. A non-positive total or
|
|
134
|
+
* member count degrades to zero caps rather than throwing.
|
|
135
|
+
*/
|
|
136
|
+
export declare function allocateBudget(options: BudgetAllocationOptions): BudgetAllocation;
|
|
137
|
+
export interface CandidateScoreOptions {
|
|
138
|
+
readonly account: BillingAccount | undefined;
|
|
139
|
+
readonly demoteThreshold: number;
|
|
140
|
+
readonly promoteCheap: boolean;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Score one candidate for ordering (lower sorts earlier). A candidate with no
|
|
144
|
+
* known billing account scores neutral so it keeps its static position. The
|
|
145
|
+
* bands: a hard-exhausted account sinks to the back; a near-cap account is
|
|
146
|
+
* demoted; cost rank nudges commodity tiers toward the cheapest ration; an
|
|
147
|
+
* operator `prefer` nudge pulls a provider earlier. Pure.
|
|
148
|
+
*/
|
|
149
|
+
export declare function candidateScore(options: CandidateScoreOptions): number;
|
|
150
|
+
export interface OrderCandidatesOptions {
|
|
151
|
+
readonly billing: BillingContext;
|
|
152
|
+
readonly demoteThreshold?: number | undefined;
|
|
153
|
+
readonly env?: RoutingEnv | undefined;
|
|
154
|
+
readonly route: RouteContext;
|
|
155
|
+
readonly tier: AiTier;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Reorder a tier's usable candidates by the billing policy, returning the
|
|
159
|
+
* runtime-fallback sequence (most-preferred first). Wraps
|
|
160
|
+
* `usableTierCandidates` — it never mutates the static `TIER_CHAINS`. The sort
|
|
161
|
+
* is stable on the original preference index, so candidates that score equal
|
|
162
|
+
* keep their static order (the Claude head stays first among equals).
|
|
163
|
+
*
|
|
164
|
+
* - In `ci`, or on a high-value tier (opus/fable), cost rank does NOT apply: the
|
|
165
|
+
* static quality-first order holds and only budget demotion / exhaustion
|
|
166
|
+
* reorders it.
|
|
167
|
+
* - In `local` on a commodity tier (haiku/sonnet), the cheapest billing kind is
|
|
168
|
+
* promoted ahead of a pricier equivalent, preserving the metered budget for
|
|
169
|
+
* the work that needs it.
|
|
170
|
+
*/
|
|
171
|
+
export declare function orderCandidates(options: OrderCandidatesOptions): TierCandidate[];
|
|
172
|
+
/**
|
|
173
|
+
* Resolve a task class to its capability tier, defaulting to `sonnet` for an
|
|
174
|
+
* unknown label so a stray string degrades safely rather than yielding
|
|
175
|
+
* `undefined`.
|
|
176
|
+
*/
|
|
177
|
+
export declare function taskClassToTier(taskClass: TaskClass): AiTier;
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/* Socket Lib - Built with rolldown */
|
|
3
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
4
|
+
const require_ai_route = require('./route.js');
|
|
5
|
+
|
|
6
|
+
//#region src/ai/route-heuristic.mts
|
|
7
|
+
/**
|
|
8
|
+
* @file Billing-aware routing heuristic — a PURE policy layer over `route.mts`.
|
|
9
|
+
* `route.mts` answers "which cross-engine candidates for this tier are
|
|
10
|
+
* installed + keyed, in static preference order"; this module answers "given
|
|
11
|
+
* how each provider is BILLED (a subscription seat vs a flat-rate plan vs
|
|
12
|
+
* metered dollars), how much budget headroom remains, and whether we're in
|
|
13
|
+
* local dev or a locked-down CI — REORDER those candidates so the cheapest
|
|
14
|
+
* ration that still meets the tier's quality bar runs first." It is pure (no
|
|
15
|
+
* I/O): a caller fans out the billing / headroom probes once (the discovery
|
|
16
|
+
* layer) and passes a `BillingContext` in, exactly as `route.mts` takes a
|
|
17
|
+
* probed `RouteContext`. The candidates within a tier chain are cross-engine
|
|
18
|
+
* EQUIVALENTS at that capability level, so reordering them by cost is safe —
|
|
19
|
+
* the tier already fixed the quality bar. NO per-user constants live here.
|
|
20
|
+
* Every dollar limit, plan tier, member count, and promo window is DATA on
|
|
21
|
+
* the passed-in context; this file is formula + ordering only, so the same
|
|
22
|
+
* policy serves a metered org with a big budget, a free-promo subscription
|
|
23
|
+
* seat, a shared team pool, or a member with no credentials at all. Even
|
|
24
|
+
* "which model is suspended" is not encoded here — that is the
|
|
25
|
+
* route/availability layer's concern. Two design choices keep it a "sweet
|
|
26
|
+
* spot" rather than a blunt cost-sort: high-value tiers (opus/fable) stay
|
|
27
|
+
* QUALITY-FIRST (the Claude head leads) and only DEMOTE an account under
|
|
28
|
+
* budget pressure, while commodity tiers (haiku/sonnet) in local dev PROMOTE
|
|
29
|
+
* the cheapest equivalent to preserve the metered budget for work that needs
|
|
30
|
+
* it; and CI keeps the locked static order so a headless run never reorders
|
|
31
|
+
* away from its single available provider.
|
|
32
|
+
*/
|
|
33
|
+
/**
|
|
34
|
+
* Canonical task-class → tier. The class fixes the capability bar; the tier
|
|
35
|
+
* chain then offers cross-engine equivalents at that bar for billing to
|
|
36
|
+
* reorder.
|
|
37
|
+
*
|
|
38
|
+
* - `grunt` → `haiku` — classify / summarize / single-token rewrites.
|
|
39
|
+
* - `code` → `sonnet` — control-flow / caller-chain edits, feature work.
|
|
40
|
+
* - `agentic` → `opus` — long tool-use loops, high-value autonomous work.
|
|
41
|
+
* - `plan` → `opus` — decomposition / architecture (escalate to `fable` only
|
|
42
|
+
* explicitly, never by default — and only when it is not suspended).
|
|
43
|
+
*/
|
|
44
|
+
const TASK_CLASS_TIER = {
|
|
45
|
+
__proto__: null,
|
|
46
|
+
agentic: "opus",
|
|
47
|
+
code: "sonnet",
|
|
48
|
+
grunt: "haiku",
|
|
49
|
+
plan: "opus"
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* Marginal-cost rank by billing kind, cheapest ration first (lower =
|
|
53
|
+
* preferred). Used only for commodity tiers in local dev — high-value tiers
|
|
54
|
+
* stay quality-first. Flat-rate and subscription are both $0-until-cap;
|
|
55
|
+
* flat-rate leads because its window resets fast (hours) vs a subscription's
|
|
56
|
+
* weekly cap.
|
|
57
|
+
*/
|
|
58
|
+
const COST_RANK = {
|
|
59
|
+
__proto__: null,
|
|
60
|
+
"flat-rate": 0,
|
|
61
|
+
metered: 2,
|
|
62
|
+
subscription: 1
|
|
63
|
+
};
|
|
64
|
+
/**
|
|
65
|
+
* Default per-task-class budget weights for `allocateBudget`. Reserves more of
|
|
66
|
+
* a member's share for high-value work (plan/agentic) than for bulk
|
|
67
|
+
* (grunt/code). Overridable per call — these are sane defaults, not per-user
|
|
68
|
+
* values.
|
|
69
|
+
*/
|
|
70
|
+
const DEFAULT_TASK_CLASS_WEIGHTS = {
|
|
71
|
+
__proto__: null,
|
|
72
|
+
agentic: 3,
|
|
73
|
+
code: 2,
|
|
74
|
+
grunt: 1,
|
|
75
|
+
plan: 4
|
|
76
|
+
};
|
|
77
|
+
/**
|
|
78
|
+
* Headroom fraction at or below which a metered/flat-rate account is demoted
|
|
79
|
+
* (predictive backoff before the hard cap). A config knob with a sane default;
|
|
80
|
+
* callers override per `orderCandidates` call.
|
|
81
|
+
*/
|
|
82
|
+
const DEFAULT_DEMOTE_THRESHOLD = .2;
|
|
83
|
+
const BULK_TIERS = /* @__PURE__ */ new Set(["haiku", "sonnet"]);
|
|
84
|
+
const SCORE_NEAR_CAP = 100;
|
|
85
|
+
const SCORE_EXHAUSTED = 1e4;
|
|
86
|
+
const TASK_CLASSES = [
|
|
87
|
+
"agentic",
|
|
88
|
+
"code",
|
|
89
|
+
"grunt",
|
|
90
|
+
"plan"
|
|
91
|
+
];
|
|
92
|
+
/**
|
|
93
|
+
* Turn a total budget into reasonable per-member, per-task-class caps by a
|
|
94
|
+
* generic formula: split the total evenly across members, then distribute each
|
|
95
|
+
* member's share across task classes proportional to their weights. The numbers
|
|
96
|
+
* in are private; the formula is generic and committed. A non-positive total or
|
|
97
|
+
* member count degrades to zero caps rather than throwing.
|
|
98
|
+
*/
|
|
99
|
+
function allocateBudget(options) {
|
|
100
|
+
const opts = {
|
|
101
|
+
__proto__: null,
|
|
102
|
+
...options
|
|
103
|
+
};
|
|
104
|
+
const members = opts.members && opts.members > 0 ? opts.members : 1;
|
|
105
|
+
const perMember = (opts.totalUsd > 0 ? opts.totalUsd : 0) / members;
|
|
106
|
+
const weights = {
|
|
107
|
+
__proto__: null,
|
|
108
|
+
...DEFAULT_TASK_CLASS_WEIGHTS,
|
|
109
|
+
...opts.weights
|
|
110
|
+
};
|
|
111
|
+
let totalWeight = 0;
|
|
112
|
+
for (let i = 0, { length } = TASK_CLASSES; i < length; i += 1) totalWeight += weights[TASK_CLASSES[i]] ?? 0;
|
|
113
|
+
const divisor = totalWeight > 0 ? totalWeight : 1;
|
|
114
|
+
const out = { __proto__: null };
|
|
115
|
+
for (let i = 0, { length } = TASK_CLASSES; i < length; i += 1) {
|
|
116
|
+
const taskClass = TASK_CLASSES[i];
|
|
117
|
+
out[taskClass] = perMember * (weights[taskClass] ?? 0) / divisor;
|
|
118
|
+
}
|
|
119
|
+
return out;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Score one candidate for ordering (lower sorts earlier). A candidate with no
|
|
123
|
+
* known billing account scores neutral so it keeps its static position. The
|
|
124
|
+
* bands: a hard-exhausted account sinks to the back; a near-cap account is
|
|
125
|
+
* demoted; cost rank nudges commodity tiers toward the cheapest ration; an
|
|
126
|
+
* operator `prefer` nudge pulls a provider earlier. Pure.
|
|
127
|
+
*/
|
|
128
|
+
function candidateScore(options) {
|
|
129
|
+
const opts = {
|
|
130
|
+
__proto__: null,
|
|
131
|
+
...options
|
|
132
|
+
};
|
|
133
|
+
const { account } = opts;
|
|
134
|
+
if (!account) return 0;
|
|
135
|
+
let score = 0;
|
|
136
|
+
const { headroom } = account;
|
|
137
|
+
if (headroom?.exhausted) score += SCORE_EXHAUSTED;
|
|
138
|
+
else if (typeof headroom?.fraction === "number" && headroom.fraction <= opts.demoteThreshold) score += SCORE_NEAR_CAP;
|
|
139
|
+
if (opts.promoteCheap) score += COST_RANK[account.kind] ?? 0;
|
|
140
|
+
if (typeof account.prefer === "number") score -= account.prefer;
|
|
141
|
+
return score;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Reorder a tier's usable candidates by the billing policy, returning the
|
|
145
|
+
* runtime-fallback sequence (most-preferred first). Wraps
|
|
146
|
+
* `usableTierCandidates` — it never mutates the static `TIER_CHAINS`. The sort
|
|
147
|
+
* is stable on the original preference index, so candidates that score equal
|
|
148
|
+
* keep their static order (the Claude head stays first among equals).
|
|
149
|
+
*
|
|
150
|
+
* - In `ci`, or on a high-value tier (opus/fable), cost rank does NOT apply: the
|
|
151
|
+
* static quality-first order holds and only budget demotion / exhaustion
|
|
152
|
+
* reorders it.
|
|
153
|
+
* - In `local` on a commodity tier (haiku/sonnet), the cheapest billing kind is
|
|
154
|
+
* promoted ahead of a pricier equivalent, preserving the metered budget for
|
|
155
|
+
* the work that needs it.
|
|
156
|
+
*/
|
|
157
|
+
function orderCandidates(options) {
|
|
158
|
+
const opts = {
|
|
159
|
+
__proto__: null,
|
|
160
|
+
...options
|
|
161
|
+
};
|
|
162
|
+
const env = opts.env ?? "local";
|
|
163
|
+
const demoteThreshold = opts.demoteThreshold ?? .2;
|
|
164
|
+
const promoteCheap = env === "local" && BULK_TIERS.has(opts.tier);
|
|
165
|
+
const scored = require_ai_route.usableTierCandidates(opts.tier, opts.route).map((candidate, index) => ({
|
|
166
|
+
candidate,
|
|
167
|
+
index,
|
|
168
|
+
score: candidateScore({
|
|
169
|
+
account: opts.billing[candidate.provider],
|
|
170
|
+
demoteThreshold,
|
|
171
|
+
promoteCheap
|
|
172
|
+
})
|
|
173
|
+
}));
|
|
174
|
+
scored.sort((a, b) => a.score - b.score || a.index - b.index);
|
|
175
|
+
return scored.map((entry) => entry.candidate);
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Resolve a task class to its capability tier, defaulting to `sonnet` for an
|
|
179
|
+
* unknown label so a stray string degrades safely rather than yielding
|
|
180
|
+
* `undefined`.
|
|
181
|
+
*/
|
|
182
|
+
function taskClassToTier(taskClass) {
|
|
183
|
+
return TASK_CLASS_TIER[taskClass] ?? "sonnet";
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
//#endregion
|
|
187
|
+
exports.COST_RANK = COST_RANK;
|
|
188
|
+
exports.DEFAULT_DEMOTE_THRESHOLD = DEFAULT_DEMOTE_THRESHOLD;
|
|
189
|
+
exports.DEFAULT_TASK_CLASS_WEIGHTS = DEFAULT_TASK_CLASS_WEIGHTS;
|
|
190
|
+
exports.TASK_CLASS_TIER = TASK_CLASS_TIER;
|
|
191
|
+
exports.allocateBudget = allocateBudget;
|
|
192
|
+
exports.candidateScore = candidateScore;
|
|
193
|
+
exports.orderCandidates = orderCandidates;
|
|
194
|
+
exports.taskClassToTier = taskClassToTier;
|