@homeflare/alchemy 0.43.0 → 0.45.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -1
- package/dist/caddy/index.js +35 -1
- package/dist/caddy/index.js.map +3 -3
- package/dist/launchd/index.js +35 -1
- package/dist/launchd/index.js.map +3 -3
- package/dist/linux/index.js +35 -1
- package/dist/linux/index.js.map +3 -3
- package/dist/litellm/access-group-form.d.ts +26 -0
- package/dist/litellm/access-group-form.d.ts.map +1 -0
- package/dist/litellm/access-group-operations.d.ts +37 -0
- package/dist/litellm/access-group-operations.d.ts.map +1 -0
- package/dist/litellm/access-group-types.d.ts +49 -0
- package/dist/litellm/access-group-types.d.ts.map +1 -0
- package/dist/litellm/access-group.d.ts +55 -0
- package/dist/litellm/access-group.d.ts.map +1 -0
- package/dist/litellm/credential-errors.d.ts +131 -0
- package/dist/litellm/credential-errors.d.ts.map +1 -0
- package/dist/litellm/credential-form.d.ts +79 -0
- package/dist/litellm/credential-form.d.ts.map +1 -0
- package/dist/litellm/credential-operations.d.ts +84 -0
- package/dist/litellm/credential-operations.d.ts.map +1 -0
- package/dist/litellm/credential-rewrite.d.ts +6 -0
- package/dist/litellm/credential-rewrite.d.ts.map +1 -0
- package/dist/litellm/credential-types.d.ts +87 -0
- package/dist/litellm/credential-types.d.ts.map +1 -0
- package/dist/litellm/credential-values.d.ts +53 -0
- package/dist/litellm/credential-values.d.ts.map +1 -0
- package/dist/litellm/credential.d.ts +83 -0
- package/dist/litellm/credential.d.ts.map +1 -0
- package/dist/litellm/fake-access-group-litellm.d.ts +34 -0
- package/dist/litellm/fake-access-group-litellm.d.ts.map +1 -0
- package/dist/litellm/fake-credential-litellm.d.ts +54 -0
- package/dist/litellm/fake-credential-litellm.d.ts.map +1 -0
- package/dist/litellm/fake-keys.d.ts +53 -0
- package/dist/litellm/fake-keys.d.ts.map +1 -0
- package/dist/litellm/fake-litellm.d.ts +4 -1
- package/dist/litellm/fake-litellm.d.ts.map +1 -1
- package/dist/litellm/fake-mcp-litellm.d.ts +67 -0
- package/dist/litellm/fake-mcp-litellm.d.ts.map +1 -0
- package/dist/litellm/fake-model-litellm-post-update.d.ts +49 -0
- package/dist/litellm/fake-model-litellm-post-update.d.ts.map +1 -0
- package/dist/litellm/fake-model-litellm.d.ts +48 -0
- package/dist/litellm/fake-model-litellm.d.ts.map +1 -0
- package/dist/litellm/fake-policy-attachment-litellm.d.ts +33 -0
- package/dist/litellm/fake-policy-attachment-litellm.d.ts.map +1 -0
- package/dist/litellm/fake-policy-litellm.d.ts +32 -0
- package/dist/litellm/fake-policy-litellm.d.ts.map +1 -0
- package/dist/litellm/fake-registry-base.d.ts +42 -0
- package/dist/litellm/fake-registry-base.d.ts.map +1 -0
- package/dist/litellm/fake-stack.d.ts +8 -1
- package/dist/litellm/fake-stack.d.ts.map +1 -1
- package/dist/litellm/fake-team-litellm.d.ts +47 -0
- package/dist/litellm/fake-team-litellm.d.ts.map +1 -0
- package/dist/litellm/fake-tool-litellm.d.ts +28 -0
- package/dist/litellm/fake-tool-litellm.d.ts.map +1 -0
- package/dist/litellm/fake-toolset-litellm.d.ts +29 -0
- package/dist/litellm/fake-toolset-litellm.d.ts.map +1 -0
- package/dist/litellm/index.d.ts +18 -0
- package/dist/litellm/index.d.ts.map +1 -1
- package/dist/litellm/index.js +3078 -2
- package/dist/litellm/index.js.map +65 -4
- package/dist/litellm/key-errors.d.ts +169 -0
- package/dist/litellm/key-errors.d.ts.map +1 -0
- package/dist/litellm/key-form.d.ts +119 -0
- package/dist/litellm/key-form.d.ts.map +1 -0
- package/dist/litellm/key-harness.d.ts +41 -0
- package/dist/litellm/key-harness.d.ts.map +1 -0
- package/dist/litellm/key-metadata-errors.d.ts +30 -0
- package/dist/litellm/key-metadata-errors.d.ts.map +1 -0
- package/dist/litellm/key-metadata.d.ts +22 -0
- package/dist/litellm/key-metadata.d.ts.map +1 -0
- package/dist/litellm/key-operations.d.ts +63 -0
- package/dist/litellm/key-operations.d.ts.map +1 -0
- package/dist/litellm/key-secret.d.ts +33 -0
- package/dist/litellm/key-secret.d.ts.map +1 -0
- package/dist/litellm/key.d.ts +78 -0
- package/dist/litellm/key.d.ts.map +1 -0
- package/dist/litellm/mcp-server-credential.d.ts +50 -0
- package/dist/litellm/mcp-server-credential.d.ts.map +1 -0
- package/dist/litellm/mcp-server-errors.d.ts +101 -0
- package/dist/litellm/mcp-server-errors.d.ts.map +1 -0
- package/dist/litellm/mcp-server-form.d.ts +56 -0
- package/dist/litellm/mcp-server-form.d.ts.map +1 -0
- package/dist/litellm/mcp-server-locate.d.ts +26 -0
- package/dist/litellm/mcp-server-locate.d.ts.map +1 -0
- package/dist/litellm/mcp-server-operations.d.ts +63 -0
- package/dist/litellm/mcp-server-operations.d.ts.map +1 -0
- package/dist/litellm/mcp-server-shadow.d.ts +24 -0
- package/dist/litellm/mcp-server-shadow.d.ts.map +1 -0
- package/dist/litellm/mcp-server-types.d.ts +118 -0
- package/dist/litellm/mcp-server-types.d.ts.map +1 -0
- package/dist/litellm/mcp-server-url.d.ts +11 -0
- package/dist/litellm/mcp-server-url.d.ts.map +1 -0
- package/dist/litellm/mcp-server.d.ts +95 -0
- package/dist/litellm/mcp-server.d.ts.map +1 -0
- package/dist/litellm/model-claim.d.ts +24 -0
- package/dist/litellm/model-claim.d.ts.map +1 -0
- package/dist/litellm/model-credential.d.ts +12 -0
- package/dist/litellm/model-credential.d.ts.map +1 -0
- package/dist/litellm/model-errors.d.ts +119 -0
- package/dist/litellm/model-errors.d.ts.map +1 -0
- package/dist/litellm/model-form.d.ts +78 -0
- package/dist/litellm/model-form.d.ts.map +1 -0
- package/dist/litellm/model-locate.d.ts +13 -0
- package/dist/litellm/model-locate.d.ts.map +1 -0
- package/dist/litellm/model-operations.d.ts +59 -0
- package/dist/litellm/model-operations.d.ts.map +1 -0
- package/dist/litellm/model-types.d.ts +91 -0
- package/dist/litellm/model-types.d.ts.map +1 -0
- package/dist/litellm/model.d.ts +88 -0
- package/dist/litellm/model.d.ts.map +1 -0
- package/dist/litellm/policy-attachment-form.d.ts +19 -0
- package/dist/litellm/policy-attachment-form.d.ts.map +1 -0
- package/dist/litellm/policy-attachment-operations.d.ts +31 -0
- package/dist/litellm/policy-attachment-operations.d.ts.map +1 -0
- package/dist/litellm/policy-attachment-types.d.ts +48 -0
- package/dist/litellm/policy-attachment-types.d.ts.map +1 -0
- package/dist/litellm/policy-attachment.d.ts +61 -0
- package/dist/litellm/policy-attachment.d.ts.map +1 -0
- package/dist/litellm/policy-form.d.ts +22 -0
- package/dist/litellm/policy-form.d.ts.map +1 -0
- package/dist/litellm/policy-operations.d.ts +42 -0
- package/dist/litellm/policy-operations.d.ts.map +1 -0
- package/dist/litellm/policy-types.d.ts +57 -0
- package/dist/litellm/policy-types.d.ts.map +1 -0
- package/dist/litellm/policy.d.ts +65 -0
- package/dist/litellm/policy.d.ts.map +1 -0
- package/dist/litellm/providers.d.ts +1 -1
- package/dist/litellm/providers.d.ts.map +1 -1
- package/dist/litellm/registry-errors.d.ts +62 -0
- package/dist/litellm/registry-errors.d.ts.map +1 -0
- package/dist/litellm/registry-support.d.ts +42 -0
- package/dist/litellm/registry-support.d.ts.map +1 -0
- package/dist/litellm/team-form.d.ts +26 -0
- package/dist/litellm/team-form.d.ts.map +1 -0
- package/dist/litellm/team-members.d.ts +10 -0
- package/dist/litellm/team-members.d.ts.map +1 -0
- package/dist/litellm/team-operations.d.ts +38 -0
- package/dist/litellm/team-operations.d.ts.map +1 -0
- package/dist/litellm/team-permission.d.ts +35 -0
- package/dist/litellm/team-permission.d.ts.map +1 -0
- package/dist/litellm/team-types.d.ts +101 -0
- package/dist/litellm/team-types.d.ts.map +1 -0
- package/dist/litellm/team.d.ts +67 -0
- package/dist/litellm/team.d.ts.map +1 -0
- package/dist/litellm/tool-policy-form.d.ts +21 -0
- package/dist/litellm/tool-policy-form.d.ts.map +1 -0
- package/dist/litellm/tool-policy-operations.d.ts +30 -0
- package/dist/litellm/tool-policy-operations.d.ts.map +1 -0
- package/dist/litellm/tool-policy-types.d.ts +46 -0
- package/dist/litellm/tool-policy-types.d.ts.map +1 -0
- package/dist/litellm/tool-policy.d.ts +62 -0
- package/dist/litellm/tool-policy.d.ts.map +1 -0
- package/dist/litellm/toolset-form.d.ts +20 -0
- package/dist/litellm/toolset-form.d.ts.map +1 -0
- package/dist/litellm/toolset-operations.d.ts +39 -0
- package/dist/litellm/toolset-operations.d.ts.map +1 -0
- package/dist/litellm/toolset-types.d.ts +46 -0
- package/dist/litellm/toolset-types.d.ts.map +1 -0
- package/dist/litellm/toolset.d.ts +55 -0
- package/dist/litellm/toolset.d.ts.map +1 -0
- package/dist/openbao/index.js +35 -1
- package/dist/openbao/index.js.map +3 -3
- package/dist/ownership/rows.d.ts +11 -0
- package/dist/ownership/rows.d.ts.map +1 -1
- package/dist/postgres/connection.d.ts +14 -2
- package/dist/postgres/connection.d.ts.map +1 -1
- package/dist/postgres/database-sql.d.ts +27 -8
- package/dist/postgres/database-sql.d.ts.map +1 -1
- package/dist/postgres/fake-grants-parse.d.ts +37 -0
- package/dist/postgres/fake-grants-parse.d.ts.map +1 -0
- package/dist/postgres/fake-grants-read.d.ts +61 -0
- package/dist/postgres/fake-grants-read.d.ts.map +1 -0
- package/dist/postgres/fake-grants-sql.d.ts +46 -0
- package/dist/postgres/fake-grants-sql.d.ts.map +1 -0
- package/dist/postgres/fake-grants-write.d.ts +29 -0
- package/dist/postgres/fake-grants-write.d.ts.map +1 -0
- package/dist/postgres/fake-role-sql.d.ts +41 -0
- package/dist/postgres/fake-role-sql.d.ts.map +1 -0
- package/dist/postgres/fake-schema-sql.d.ts +42 -0
- package/dist/postgres/fake-schema-sql.d.ts.map +1 -0
- package/dist/postgres/fake-sql-parse.d.ts +23 -0
- package/dist/postgres/fake-sql-parse.d.ts.map +1 -0
- package/dist/postgres/fake-sql-quote.d.ts +12 -0
- package/dist/postgres/fake-sql-quote.d.ts.map +1 -0
- package/dist/postgres/fake-sql.d.ts +42 -0
- package/dist/postgres/fake-sql.d.ts.map +1 -1
- package/dist/postgres/grants-attrs.d.ts +115 -0
- package/dist/postgres/grants-attrs.d.ts.map +1 -0
- package/dist/postgres/grants-declare.d.ts +88 -0
- package/dist/postgres/grants-declare.d.ts.map +1 -0
- package/dist/postgres/grants-diff.d.ts +25 -0
- package/dist/postgres/grants-diff.d.ts.map +1 -0
- package/dist/postgres/grants-errors.d.ts +137 -0
- package/dist/postgres/grants-errors.d.ts.map +1 -0
- package/dist/postgres/grants-existence.d.ts +14 -0
- package/dist/postgres/grants-existence.d.ts.map +1 -0
- package/dist/postgres/grants-ops.d.ts +65 -0
- package/dist/postgres/grants-ops.d.ts.map +1 -0
- package/dist/postgres/grants-ownership.d.ts +18 -0
- package/dist/postgres/grants-ownership.d.ts.map +1 -0
- package/dist/postgres/grants-plan-restore.d.ts +22 -0
- package/dist/postgres/grants-plan-restore.d.ts.map +1 -0
- package/dist/postgres/grants-plan.d.ts +65 -0
- package/dist/postgres/grants-plan.d.ts.map +1 -0
- package/dist/postgres/grants-read-defaults.d.ts +17 -0
- package/dist/postgres/grants-read-defaults.d.ts.map +1 -0
- package/dist/postgres/grants-read.d.ts +77 -0
- package/dist/postgres/grants-read.d.ts.map +1 -0
- package/dist/postgres/grants-refuse.d.ts +25 -0
- package/dist/postgres/grants-refuse.d.ts.map +1 -0
- package/dist/postgres/grants-sql.d.ts +42 -0
- package/dist/postgres/grants-sql.d.ts.map +1 -0
- package/dist/postgres/grants-words.d.ts +29 -0
- package/dist/postgres/grants-words.d.ts.map +1 -0
- package/dist/postgres/grants.d.ts +37 -0
- package/dist/postgres/grants.d.ts.map +1 -0
- package/dist/postgres/index.d.ts +31 -6
- package/dist/postgres/index.d.ts.map +1 -1
- package/dist/postgres/index.js +1998 -37
- package/dist/postgres/index.js.map +46 -7
- package/dist/postgres/installed-classifier.d.ts +13 -0
- package/dist/postgres/installed-classifier.d.ts.map +1 -0
- package/dist/postgres/providers.d.ts +16 -8
- package/dist/postgres/providers.d.ts.map +1 -1
- package/dist/postgres/psql-executor.d.ts +4 -0
- package/dist/postgres/psql-executor.d.ts.map +1 -1
- package/dist/postgres/role-attrs.d.ts +112 -0
- package/dist/postgres/role-attrs.d.ts.map +1 -0
- package/dist/postgres/role-diff.d.ts +22 -0
- package/dist/postgres/role-diff.d.ts.map +1 -0
- package/dist/postgres/role-errors.d.ts +132 -0
- package/dist/postgres/role-errors.d.ts.map +1 -0
- package/dist/postgres/role-membership-sql.d.ts +78 -0
- package/dist/postgres/role-membership-sql.d.ts.map +1 -0
- package/dist/postgres/role-provider.d.ts +11 -0
- package/dist/postgres/role-provider.d.ts.map +1 -0
- package/dist/postgres/role-scram.d.ts +8 -0
- package/dist/postgres/role-scram.d.ts.map +1 -0
- package/dist/postgres/role-secrets.d.ts +38 -0
- package/dist/postgres/role-secrets.d.ts.map +1 -0
- package/dist/postgres/role-sql.d.ts +68 -0
- package/dist/postgres/role-sql.d.ts.map +1 -0
- package/dist/postgres/role.d.ts +57 -0
- package/dist/postgres/role.d.ts.map +1 -0
- package/dist/postgres/schema-assert.d.ts +50 -0
- package/dist/postgres/schema-assert.d.ts.map +1 -0
- package/dist/postgres/schema-attrs.d.ts +51 -0
- package/dist/postgres/schema-attrs.d.ts.map +1 -0
- package/dist/postgres/schema-delete.d.ts +28 -0
- package/dist/postgres/schema-delete.d.ts.map +1 -0
- package/dist/postgres/schema-diff.d.ts +14 -0
- package/dist/postgres/schema-diff.d.ts.map +1 -0
- package/dist/postgres/schema-errors.d.ts +139 -0
- package/dist/postgres/schema-errors.d.ts.map +1 -0
- package/dist/postgres/schema-identity.d.ts +8 -0
- package/dist/postgres/schema-identity.d.ts.map +1 -0
- package/dist/postgres/schema-reconcile.d.ts +12 -0
- package/dist/postgres/schema-reconcile.d.ts.map +1 -0
- package/dist/postgres/schema-sql.d.ts +45 -0
- package/dist/postgres/schema-sql.d.ts.map +1 -0
- package/dist/postgres/schema-test-kit.d.ts +67 -0
- package/dist/postgres/schema-test-kit.d.ts.map +1 -0
- package/dist/postgres/schema.d.ts +54 -0
- package/dist/postgres/schema.d.ts.map +1 -0
- package/dist/proxmox/index.js +35 -1
- package/dist/proxmox/index.js.map +3 -3
- package/dist/release/fake-engine.d.ts +10 -0
- package/dist/release/fake-engine.d.ts.map +1 -1
- package/dist/release/index.js +35 -1
- package/dist/release/index.js.map +3 -3
- package/dist/valkey/acl-attrs.d.ts +94 -0
- package/dist/valkey/acl-attrs.d.ts.map +1 -0
- package/dist/valkey/acl-compare.d.ts +28 -0
- package/dist/valkey/acl-compare.d.ts.map +1 -0
- package/dist/valkey/acl-connection.d.ts +6 -0
- package/dist/valkey/acl-connection.d.ts.map +1 -0
- package/dist/valkey/acl-form.d.ts +62 -0
- package/dist/valkey/acl-form.d.ts.map +1 -0
- package/dist/valkey/acl-managed.d.ts +4 -0
- package/dist/valkey/acl-managed.d.ts.map +1 -0
- package/dist/valkey/acl-ops.d.ts +37 -0
- package/dist/valkey/acl-ops.d.ts.map +1 -0
- package/dist/valkey/acl-profiles.d.ts +53 -0
- package/dist/valkey/acl-profiles.d.ts.map +1 -0
- package/dist/valkey/acl-reconcile.d.ts +26 -0
- package/dist/valkey/acl-reconcile.d.ts.map +1 -0
- package/dist/valkey/acl.d.ts +24 -0
- package/dist/valkey/acl.d.ts.map +1 -0
- package/dist/valkey/connection-service.d.ts +22 -0
- package/dist/valkey/connection-service.d.ts.map +1 -0
- package/dist/valkey/connection.d.ts +59 -0
- package/dist/valkey/connection.d.ts.map +1 -0
- package/dist/valkey/errors.d.ts +165 -0
- package/dist/valkey/errors.d.ts.map +1 -0
- package/dist/valkey/fake-acl.d.ts +29 -0
- package/dist/valkey/fake-acl.d.ts.map +1 -0
- package/dist/valkey/fake-valkey.d.ts +35 -0
- package/dist/valkey/fake-valkey.d.ts.map +1 -0
- package/dist/valkey/handler-test-fixture.d.ts +20 -0
- package/dist/valkey/handler-test-fixture.d.ts.map +1 -0
- package/dist/valkey/index.d.ts +18 -0
- package/dist/valkey/index.d.ts.map +1 -0
- package/dist/valkey/index.js +964 -0
- package/dist/valkey/index.js.map +27 -0
- package/dist/valkey/instance-attrs.d.ts +46 -0
- package/dist/valkey/instance-attrs.d.ts.map +1 -0
- package/dist/valkey/instance-form.d.ts +22 -0
- package/dist/valkey/instance-form.d.ts.map +1 -0
- package/dist/valkey/instance.d.ts +48 -0
- package/dist/valkey/instance.d.ts.map +1 -0
- package/dist/valkey/provider-socket-fixture.d.ts +8 -0
- package/dist/valkey/provider-socket-fixture.d.ts.map +1 -0
- package/dist/valkey/providers.d.ts +16 -0
- package/dist/valkey/providers.d.ts.map +1 -0
- package/dist/valkey/resp.d.ts +38 -0
- package/dist/valkey/resp.d.ts.map +1 -0
- package/dist/valkey/transport-error.d.ts +36 -0
- package/dist/valkey/transport-error.d.ts.map +1 -0
- package/dist/valkey/transport.d.ts +50 -0
- package/dist/valkey/transport.d.ts.map +1 -0
- package/docs/litellm-access-group.md +105 -0
- package/docs/litellm-credential.md +60 -0
- package/docs/litellm-key-metadata.md +56 -0
- package/docs/litellm-key.md +194 -0
- package/docs/litellm-mcp.md +187 -0
- package/docs/litellm-model.md +111 -0
- package/docs/litellm-policy-attachment.md +86 -0
- package/docs/litellm-policy.md +103 -0
- package/docs/litellm-team.md +117 -0
- package/docs/litellm-tool-policy.md +90 -0
- package/docs/litellm-toolset.md +92 -0
- package/docs/litellm.md +16 -9
- package/docs/peers.md +15 -6
- package/docs/postgres-grants-example.md +55 -0
- package/docs/postgres-grants.md +157 -0
- package/docs/postgres-role.md +126 -0
- package/docs/postgres-schema.md +139 -0
- package/docs/postgres.md +20 -3
- package/docs/valkey-transport.md +29 -0
- package/docs/valkey.md +187 -0
- package/package.json +6 -2
- package/src/ceph/ceph-argv.test.ts +1 -1
- package/src/launchd/sudo-allowlist.test.ts +2 -2
- package/src/linux/sudo-allowlist.test.ts +3 -3
- package/src/linux/sudo-runner.test.ts +2 -2
- package/src/litellm/access-group-form.ts +105 -0
- package/src/litellm/access-group-operations.ts +92 -0
- package/src/litellm/access-group-types.ts +49 -0
- package/src/litellm/access-group.test.ts +197 -0
- package/src/litellm/access-group.ts +151 -0
- package/src/litellm/credential-errors.ts +183 -0
- package/src/litellm/credential-form.test.ts +151 -0
- package/src/litellm/credential-form.ts +211 -0
- package/src/litellm/credential-guards.test.ts +241 -0
- package/src/litellm/credential-operations.ts +208 -0
- package/src/litellm/credential-recovery.test.ts +93 -0
- package/src/litellm/credential-rewrite.test.ts +164 -0
- package/src/litellm/credential-rewrite.ts +50 -0
- package/src/litellm/credential-types.ts +117 -0
- package/src/litellm/credential-values.ts +94 -0
- package/src/litellm/credential.test.ts +218 -0
- package/src/litellm/credential.ts +227 -0
- package/src/litellm/fake-access-group-litellm.ts +127 -0
- package/src/litellm/fake-credential-litellm.ts +216 -0
- package/src/litellm/fake-keys.ts +190 -0
- package/src/litellm/fake-litellm.ts +19 -9
- package/src/litellm/fake-mcp-litellm.ts +214 -0
- package/src/litellm/fake-model-litellm-post-update.ts +103 -0
- package/src/litellm/fake-model-litellm.ts +233 -0
- package/src/litellm/fake-policy-attachment-litellm.ts +97 -0
- package/src/litellm/fake-policy-litellm.ts +186 -0
- package/src/litellm/fake-registry-base.ts +69 -0
- package/src/litellm/fake-stack.ts +17 -1
- package/src/litellm/fake-team-litellm.ts +229 -0
- package/src/litellm/fake-tool-litellm.ts +88 -0
- package/src/litellm/fake-toolset-litellm.ts +110 -0
- package/src/litellm/index.ts +140 -0
- package/src/litellm/key-delete.test.ts +212 -0
- package/src/litellm/key-errors.ts +241 -0
- package/src/litellm/key-form.ts +200 -0
- package/src/litellm/key-harness.ts +121 -0
- package/src/litellm/key-metadata-errors.ts +49 -0
- package/src/litellm/key-metadata.test.ts +156 -0
- package/src/litellm/key-metadata.ts +74 -0
- package/src/litellm/key-operations.ts +184 -0
- package/src/litellm/key-rotation.test.ts +110 -0
- package/src/litellm/key-scope.test.ts +135 -0
- package/src/litellm/key-secret.test.ts +248 -0
- package/src/litellm/key-secret.ts +137 -0
- package/src/litellm/key-transport.test.ts +166 -0
- package/src/litellm/key.test.ts +231 -0
- package/src/litellm/key.ts +213 -0
- package/src/litellm/mcp-server-adopt.test.ts +86 -0
- package/src/litellm/mcp-server-alias.test.ts +184 -0
- package/src/litellm/mcp-server-credential.ts +85 -0
- package/src/litellm/mcp-server-errors.ts +141 -0
- package/src/litellm/mcp-server-exports.test.ts +15 -0
- package/src/litellm/mcp-server-form.test.ts +241 -0
- package/src/litellm/mcp-server-form.ts +233 -0
- package/src/litellm/mcp-server-handlers.test.ts +150 -0
- package/src/litellm/mcp-server-locate.ts +66 -0
- package/src/litellm/mcp-server-operations.ts +111 -0
- package/src/litellm/mcp-server-registry.test.ts +146 -0
- package/src/litellm/mcp-server-retype.test.ts +114 -0
- package/src/litellm/mcp-server-shadow.test.ts +91 -0
- package/src/litellm/mcp-server-shadow.ts +45 -0
- package/src/litellm/mcp-server-tools.test.ts +85 -0
- package/src/litellm/mcp-server-types.ts +143 -0
- package/src/litellm/mcp-server-url.ts +66 -0
- package/src/litellm/mcp-server.test.ts +213 -0
- package/src/litellm/mcp-server.ts +225 -0
- package/src/litellm/model-claim.ts +69 -0
- package/src/litellm/model-credential.ts +45 -0
- package/src/litellm/model-errors.ts +168 -0
- package/src/litellm/model-foreign-row.test.ts +173 -0
- package/src/litellm/model-form.test.ts +228 -0
- package/src/litellm/model-form.ts +223 -0
- package/src/litellm/model-locate.test.ts +128 -0
- package/src/litellm/model-locate.ts +67 -0
- package/src/litellm/model-operations.test.ts +93 -0
- package/src/litellm/model-operations.ts +146 -0
- package/src/litellm/model-params-preserve.test.ts +119 -0
- package/src/litellm/model-recovery.test.ts +57 -0
- package/src/litellm/model-types.ts +112 -0
- package/src/litellm/model.test.ts +222 -0
- package/src/litellm/model.ts +237 -0
- package/src/litellm/policy-attachment-form.ts +103 -0
- package/src/litellm/policy-attachment-operations.ts +74 -0
- package/src/litellm/policy-attachment-types.ts +48 -0
- package/src/litellm/policy-attachment.test.ts +198 -0
- package/src/litellm/policy-attachment.ts +178 -0
- package/src/litellm/policy-form.ts +122 -0
- package/src/litellm/policy-operations.ts +112 -0
- package/src/litellm/policy-types.ts +58 -0
- package/src/litellm/policy.test.ts +214 -0
- package/src/litellm/policy.ts +146 -0
- package/src/litellm/providers.ts +24 -3
- package/src/litellm/registry-errors.ts +88 -0
- package/src/litellm/registry-exports.test.ts +66 -0
- package/src/litellm/registry-support.ts +109 -0
- package/src/litellm/team-form.ts +140 -0
- package/src/litellm/team-members.test.ts +150 -0
- package/src/litellm/team-members.ts +58 -0
- package/src/litellm/team-operations.ts +90 -0
- package/src/litellm/team-permission.ts +159 -0
- package/src/litellm/team-read.test.ts +89 -0
- package/src/litellm/team-types.ts +106 -0
- package/src/litellm/team.test.ts +206 -0
- package/src/litellm/team.ts +159 -0
- package/src/litellm/tool-policy-form.ts +94 -0
- package/src/litellm/tool-policy-operations.ts +58 -0
- package/src/litellm/tool-policy-types.ts +48 -0
- package/src/litellm/tool-policy.test.ts +172 -0
- package/src/litellm/tool-policy.ts +125 -0
- package/src/litellm/toolset-form.ts +104 -0
- package/src/litellm/toolset-operations.ts +90 -0
- package/src/litellm/toolset-types.ts +47 -0
- package/src/litellm/toolset.test.ts +198 -0
- package/src/litellm/toolset.ts +151 -0
- package/src/ownership/ownership.test.ts +33 -1
- package/src/ownership/rows.ts +53 -0
- package/src/postgres/connection.ts +42 -7
- package/src/postgres/database-bigint-serialization.test.ts +1 -0
- package/src/postgres/database-refusals.test.ts +2 -2
- package/src/postgres/database-sql.ts +36 -9
- package/src/postgres/fake-grants-parse.ts +189 -0
- package/src/postgres/fake-grants-read.ts +250 -0
- package/src/postgres/fake-grants-sql.ts +207 -0
- package/src/postgres/fake-grants-write.ts +90 -0
- package/src/postgres/fake-role-sql.ts +240 -0
- package/src/postgres/fake-schema-semantics.test.ts +36 -0
- package/src/postgres/fake-schema-sql.ts +146 -0
- package/src/postgres/fake-sql-parse.ts +86 -0
- package/src/postgres/fake-sql-quote.ts +36 -0
- package/src/postgres/fake-sql.ts +166 -46
- package/src/postgres/fixtures/pg-REL_18_6-acl.h.txt +147 -0
- package/src/postgres/fixtures/pg-REL_18_6-aclexplode-func.txt +31 -0
- package/src/postgres/fixtures/pg-REL_18_6-alter-default-privileges-synopsis.txt +82 -0
- package/src/postgres/fixtures/pg-REL_18_6-alter_role.sgml.txt +44 -0
- package/src/postgres/fixtures/pg-REL_18_6-create_role.sgml.txt +26 -0
- package/src/postgres/fixtures/pg-REL_18_6-grant-synopsis.txt +95 -0
- package/src/postgres/fixtures/pg-REL_18_6-pg_attribute.h.txt +24 -0
- package/src/postgres/fixtures/pg-REL_18_6-pg_auth_members.h.txt +62 -0
- package/src/postgres/fixtures/pg-REL_18_6-pg_authid.h.txt +70 -0
- package/src/postgres/fixtures/pg-REL_18_6-pg_class.h.txt +33 -0
- package/src/postgres/fixtures/pg-REL_18_6-pg_default_acl.h.txt +81 -0
- package/src/postgres/fixtures/pg-REL_18_6-pg_namespace.h.txt +28 -0
- package/src/postgres/fixtures/pg-REL_18_6-revoke-synopsis.txt +124 -0
- package/src/postgres/grants-acl.test.ts +61 -0
- package/src/postgres/grants-attrs.ts +185 -0
- package/src/postgres/grants-database.test.ts +158 -0
- package/src/postgres/grants-declare.ts +172 -0
- package/src/postgres/grants-delete-proof.test.ts +154 -0
- package/src/postgres/grants-diff.ts +101 -0
- package/src/postgres/grants-errors.ts +215 -0
- package/src/postgres/grants-existence-guards.test.ts +113 -0
- package/src/postgres/grants-existence.ts +101 -0
- package/src/postgres/grants-lifecycle-guards.test.ts +208 -0
- package/src/postgres/grants-lifecycle-repair.test.ts +208 -0
- package/src/postgres/grants-lifecycle.test.ts +181 -0
- package/src/postgres/grants-ops.ts +229 -0
- package/src/postgres/grants-owner-revoke.test.ts +121 -0
- package/src/postgres/grants-ownership.ts +49 -0
- package/src/postgres/grants-plan-collateral.test.ts +202 -0
- package/src/postgres/grants-plan-diff.test.ts +204 -0
- package/src/postgres/grants-plan-restore.ts +43 -0
- package/src/postgres/grants-plan-revocations.test.ts +69 -0
- package/src/postgres/grants-plan.test.ts +148 -0
- package/src/postgres/grants-plan.ts +245 -0
- package/src/postgres/grants-provenance.test.ts +134 -0
- package/src/postgres/grants-psql-lifecycle.test.ts +105 -0
- package/src/postgres/grants-read-absent.test.ts +91 -0
- package/src/postgres/grants-read-defaults.ts +51 -0
- package/src/postgres/grants-read.ts +250 -0
- package/src/postgres/grants-refusals.test.ts +136 -0
- package/src/postgres/grants-refuse.ts +119 -0
- package/src/postgres/grants-relkind-wire.test.ts +111 -0
- package/src/postgres/grants-repair-plan.test.ts +201 -0
- package/src/postgres/grants-sql.test.ts +128 -0
- package/src/postgres/grants-sql.ts +144 -0
- package/src/postgres/grants-words.ts +34 -0
- package/src/postgres/grants.ts +110 -0
- package/src/postgres/index.ts +129 -5
- package/src/postgres/installed-classifier.ts +36 -0
- package/src/postgres/providers.ts +33 -9
- package/src/postgres/psql-executor-escaping.test.ts +67 -0
- package/src/postgres/psql-executor.test.ts +63 -2
- package/src/postgres/psql-executor.ts +74 -34
- package/src/postgres/role-adopt.test.ts +98 -0
- package/src/postgres/role-attrs.ts +137 -0
- package/src/postgres/role-diff.ts +93 -0
- package/src/postgres/role-errors.ts +206 -0
- package/src/postgres/role-guard.test.ts +60 -0
- package/src/postgres/role-identity.test.ts +197 -0
- package/src/postgres/role-lifecycle.test.ts +228 -0
- package/src/postgres/role-membership-options.test.ts +73 -0
- package/src/postgres/role-membership-repair.test.ts +153 -0
- package/src/postgres/role-membership-sql.ts +223 -0
- package/src/postgres/role-password-ascii.test.ts +53 -0
- package/src/postgres/role-password-transports.test.ts +123 -0
- package/src/postgres/role-password.test.ts +158 -0
- package/src/postgres/role-privilege.test.ts +107 -0
- package/src/postgres/role-provenance.test.ts +200 -0
- package/src/postgres/role-provider.ts +105 -0
- package/src/postgres/role-refusals.test.ts +225 -0
- package/src/postgres/role-scram.test.ts +38 -0
- package/src/postgres/role-scram.ts +40 -0
- package/src/postgres/role-secrets.ts +61 -0
- package/src/postgres/role-sql.ts +213 -0
- package/src/postgres/role-valid-until.test.ts +68 -0
- package/src/postgres/role.ts +226 -0
- package/src/postgres/schema-assert.ts +139 -0
- package/src/postgres/schema-attrs.ts +71 -0
- package/src/postgres/schema-delete-proofs.test.ts +192 -0
- package/src/postgres/schema-delete.ts +96 -0
- package/src/postgres/schema-diff.ts +44 -0
- package/src/postgres/schema-drop-2bp01.test.ts +146 -0
- package/src/postgres/schema-errors.ts +209 -0
- package/src/postgres/schema-handlers.test.ts +193 -0
- package/src/postgres/schema-identity.ts +39 -0
- package/src/postgres/schema-lifecycle.test.ts +246 -0
- package/src/postgres/schema-race.test.ts +70 -0
- package/src/postgres/schema-reconcile.ts +100 -0
- package/src/postgres/schema-refusals.test.ts +144 -0
- package/src/postgres/schema-socket.test.ts +162 -0
- package/src/postgres/schema-sql.ts +130 -0
- package/src/postgres/schema-takeover.test.ts +149 -0
- package/src/postgres/schema-test-kit.ts +85 -0
- package/src/postgres/schema.ts +130 -0
- package/src/release/binary-alias.test.ts +3 -3
- package/src/release/binary-claims.test.ts +3 -3
- package/src/release/binary-directory-umask.test.ts +65 -0
- package/src/release/fake-engine.ts +15 -0
- package/src/valkey/acl-attrs.ts +98 -0
- package/src/valkey/acl-compare.ts +57 -0
- package/src/valkey/acl-connection.ts +13 -0
- package/src/valkey/acl-delete.test.ts +127 -0
- package/src/valkey/acl-form.ts +239 -0
- package/src/valkey/acl-managed.ts +13 -0
- package/src/valkey/acl-ops.ts +122 -0
- package/src/valkey/acl-ownership.test.ts +118 -0
- package/src/valkey/acl-prefix.test.ts +38 -0
- package/src/valkey/acl-profiles.ts +81 -0
- package/src/valkey/acl-reconcile.ts +180 -0
- package/src/valkey/acl-reserved.test.ts +69 -0
- package/src/valkey/acl-revocation.test.ts +94 -0
- package/src/valkey/acl-seat-prefix.test.ts +111 -0
- package/src/valkey/acl-validation.test.ts +54 -0
- package/src/valkey/acl.test.ts +215 -0
- package/src/valkey/acl.ts +169 -0
- package/src/valkey/connection-service.ts +46 -0
- package/src/valkey/connection.ts +180 -0
- package/src/valkey/errors.ts +239 -0
- package/src/valkey/fake-acl.ts +128 -0
- package/src/valkey/fake-valkey.ts +224 -0
- package/src/valkey/handler-test-fixture.ts +43 -0
- package/src/valkey/handlers.test.ts +205 -0
- package/src/valkey/index.ts +54 -0
- package/src/valkey/instance-attrs.ts +48 -0
- package/src/valkey/instance-form.ts +104 -0
- package/src/valkey/instance.test.ts +108 -0
- package/src/valkey/instance.ts +160 -0
- package/src/valkey/provider-socket-fixture.ts +71 -0
- package/src/valkey/providers.test.ts +129 -0
- package/src/valkey/providers.ts +21 -0
- package/src/valkey/resp.ts +212 -0
- package/src/valkey/transport-bounds.test.ts +150 -0
- package/src/valkey/transport-error.ts +37 -0
- package/src/valkey/transport.test.ts +158 -0
- package/src/valkey/transport.ts +109 -0
- package/src/valkey/upstream-bounds.test.ts +14 -0
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adopt and a later params write must not clobber `litellm_params` this resource does not own.
|
|
3
|
+
*
|
|
4
|
+
* ⚠️ `fillsParamDefaults` models v1.103.0 `updateLiteLLMParams`: the parsed model fills every
|
|
5
|
+
* unset field with its pydantic default before the write, a non-`None` default (`false`)
|
|
6
|
+
* overwrites the stored value, and JSON `null` is the `None` that keeps the stored value. The
|
|
7
|
+
* real PATCH route merges — sent keys land, the rest of the row survives — which is exactly
|
|
8
|
+
* what stops the write clobbering keys the declaration does not own. This file pins that.
|
|
9
|
+
*/
|
|
10
|
+
import { expect, test } from 'bun:test';
|
|
11
|
+
import * as Effect from 'effect/Effect';
|
|
12
|
+
import { FAKE_BASE } from './fake-litellm.ts';
|
|
13
|
+
import { type FakeModelLitellm, modelRow, startFakeModelLitellm } from './fake-model-litellm.ts';
|
|
14
|
+
import { fakeStack, writesOf } from './fake-stack.ts';
|
|
15
|
+
import { LiteLLMModel } from './model.ts';
|
|
16
|
+
import type { ModelProps } from './model-types.ts';
|
|
17
|
+
|
|
18
|
+
type Row = Record<string, unknown>;
|
|
19
|
+
|
|
20
|
+
const KEY = 'sk-test-master';
|
|
21
|
+
|
|
22
|
+
const stack = (fake: FakeModelLitellm) =>
|
|
23
|
+
fakeStack({ apiKey: KEY, baseUrl: FAKE_BASE }, fake.fetch);
|
|
24
|
+
|
|
25
|
+
const declare = (props: ModelProps, name = 'Grok') =>
|
|
26
|
+
Effect.gen(function* () {
|
|
27
|
+
yield* LiteLLMModel(name, props);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
const liveParams = {
|
|
31
|
+
model: 'xai/grok-4.7',
|
|
32
|
+
use_in_pass_through: true,
|
|
33
|
+
use_xai_oauth: true,
|
|
34
|
+
'FAKE-extra-param': 'kept',
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
test('adopting a matching row stamps the seal locally and leaves unmanaged params', async () => {
|
|
38
|
+
const fake = startFakeModelLitellm({
|
|
39
|
+
fillsParamDefaults: true,
|
|
40
|
+
masterKey: KEY,
|
|
41
|
+
seed: [
|
|
42
|
+
modelRow({
|
|
43
|
+
litellm_params: liveParams,
|
|
44
|
+
model_info: { access_groups: [], id: 'FAKE-live-id' },
|
|
45
|
+
model_name: 'grok',
|
|
46
|
+
}),
|
|
47
|
+
],
|
|
48
|
+
});
|
|
49
|
+
const adopted: ModelProps = { model: 'xai/grok-4.7', modelName: 'grok' };
|
|
50
|
+
const engine = stack(fake);
|
|
51
|
+
expect(await engine.deploy(declare(adopted), { adopt: true })).toEqual({ Grok: 'adopted' });
|
|
52
|
+
expect(writesOf(fake.requests())).not.toContain('PATCH /model/FAKE-live-id/update');
|
|
53
|
+
expect(fake.models()[0]?.['litellm_params']).toEqual(liveParams);
|
|
54
|
+
expect(await engine.deploy(declare(adopted), { adopt: true })).toEqual({ Grok: 'noop' });
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
test('adopting a matching row still converges a DECLARED credential, flags intact', async () => {
|
|
58
|
+
const fake = startFakeModelLitellm({
|
|
59
|
+
fillsParamDefaults: true,
|
|
60
|
+
masterKey: KEY,
|
|
61
|
+
seed: [
|
|
62
|
+
modelRow({
|
|
63
|
+
litellm_params: {
|
|
64
|
+
model: 'xai/grok-4.7',
|
|
65
|
+
api_key: 'os.environ/FAKE_OLD_KEY',
|
|
66
|
+
use_in_pass_through: true,
|
|
67
|
+
},
|
|
68
|
+
model_info: { access_groups: [], id: 'FAKE-live-id' },
|
|
69
|
+
model_name: 'grok',
|
|
70
|
+
}),
|
|
71
|
+
],
|
|
72
|
+
});
|
|
73
|
+
// api_key is never on the read, so the row looks like a perfect match: only the declared
|
|
74
|
+
// credential reference says otherwise, and only a write can converge it (model-form.ts).
|
|
75
|
+
const adopted: ModelProps = {
|
|
76
|
+
apiKey: { fromEnv: 'FAKE_NEW_KEY' },
|
|
77
|
+
model: 'xai/grok-4.7',
|
|
78
|
+
modelName: 'grok',
|
|
79
|
+
};
|
|
80
|
+
const engine = stack(fake);
|
|
81
|
+
expect(await engine.deploy(declare(adopted), { adopt: true })).toEqual({ Grok: 'adopted' });
|
|
82
|
+
expect(writesOf(fake.requests())).toContain('PATCH /model/FAKE-live-id/update');
|
|
83
|
+
expect(fake.models()[0]?.['litellm_params']).toMatchObject({
|
|
84
|
+
api_key: 'os.environ/FAKE_NEW_KEY',
|
|
85
|
+
model: 'xai/grok-4.7',
|
|
86
|
+
use_in_pass_through: true,
|
|
87
|
+
});
|
|
88
|
+
expect(await engine.deploy(declare(adopted), { adopt: true })).toEqual({ Grok: 'noop' });
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
test('a real params write sends null for the non-None defaults and keeps extra keys', async () => {
|
|
92
|
+
const fake = startFakeModelLitellm({
|
|
93
|
+
fillsParamDefaults: true,
|
|
94
|
+
masterKey: KEY,
|
|
95
|
+
seed: [
|
|
96
|
+
modelRow({
|
|
97
|
+
litellm_params: liveParams,
|
|
98
|
+
model_info: { access_groups: [], id: 'FAKE-live-id' },
|
|
99
|
+
model_name: 'grok',
|
|
100
|
+
}),
|
|
101
|
+
],
|
|
102
|
+
});
|
|
103
|
+
const adopted: ModelProps = { model: 'xai/grok-4.6', modelName: 'grok' };
|
|
104
|
+
expect(await stack(fake).deploy(declare(adopted), { adopt: true })).toEqual({ Grok: 'adopted' });
|
|
105
|
+
const patched = fake.bodies().find((body) => body['litellm_params'] !== undefined);
|
|
106
|
+
const sent = patched?.['litellm_params'] as Row;
|
|
107
|
+
expect(sent['model']).toBe('xai/grok-4.6');
|
|
108
|
+
expect(sent['use_in_pass_through']).toBeNull();
|
|
109
|
+
expect(sent['use_litellm_proxy']).toBeNull();
|
|
110
|
+
expect(sent['use_xai_oauth']).toBeNull();
|
|
111
|
+
expect(sent['allow_client_keepalive_override']).toBeNull();
|
|
112
|
+
expect(sent['merge_reasoning_content_in_choices']).toBeNull();
|
|
113
|
+
expect(fake.models()[0]?.['litellm_params']).toMatchObject({
|
|
114
|
+
'FAKE-extra-param': 'kept',
|
|
115
|
+
model: 'xai/grok-4.6',
|
|
116
|
+
use_in_pass_through: true,
|
|
117
|
+
use_xai_oauth: true,
|
|
118
|
+
});
|
|
119
|
+
});
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A deploy that dies after `POST /model/new` and before the read-back commits attributes.
|
|
3
|
+
* The next plan resumes the same generation (`creating` or `replacing`, no attributes).
|
|
4
|
+
*
|
|
5
|
+
* ★ Through Alchemy's real Plan and Apply. `noRetry` so the injected 500 is the failure, not a
|
|
6
|
+
* backoff that then succeeds. Every value is `FAKE-*`.
|
|
7
|
+
*/
|
|
8
|
+
import { expect, test } from 'bun:test';
|
|
9
|
+
import * as Effect from 'effect/Effect';
|
|
10
|
+
import { FAKE_BASE } from './fake-litellm.ts';
|
|
11
|
+
import { type FakeModelLitellm, startFakeModelLitellm } from './fake-model-litellm.ts';
|
|
12
|
+
import { fakeStack } from './fake-stack.ts';
|
|
13
|
+
import { LiteLLMModel } from './model.ts';
|
|
14
|
+
import type { ModelProps } from './model-types.ts';
|
|
15
|
+
|
|
16
|
+
const KEY = 'sk-test-master';
|
|
17
|
+
const stack = (fake: FakeModelLitellm) =>
|
|
18
|
+
fakeStack({ apiKey: KEY, baseUrl: FAKE_BASE }, fake.fetch, 'ModelStack', { noRetry: true });
|
|
19
|
+
const declare = (props: ModelProps) =>
|
|
20
|
+
Effect.gen(function* () {
|
|
21
|
+
yield* LiteLLMModel('Grok', props);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
const rowId = (row: Record<string, unknown>): string =>
|
|
25
|
+
String((row['model_info'] as Record<string, unknown>)['id']);
|
|
26
|
+
|
|
27
|
+
test('an unpinned create interrupted after POST resumes on the next deploy', async () => {
|
|
28
|
+
const fake = startFakeModelLitellm({ masterKey: KEY });
|
|
29
|
+
const engine = stack(fake);
|
|
30
|
+
const props: ModelProps = { model: 'xai/grok-4.7', modelName: 'grok' };
|
|
31
|
+
fake.failNextReadBacks(1);
|
|
32
|
+
await expect(engine.deploy(declare(props))).rejects.toThrow(/injected read-back failure/);
|
|
33
|
+
expect(fake.models()).toHaveLength(1);
|
|
34
|
+
// The recovery read's instance id is the creating row's, so the physical name matches and the
|
|
35
|
+
// row is ours. No --adopt.
|
|
36
|
+
expect(await engine.deploy(declare(props))).toEqual({ Grok: 'create' });
|
|
37
|
+
expect(await engine.deploy(declare(props))).toEqual({ Grok: 'noop' });
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test('a declared-id replace whose read-back 500s resumes with --adopt', async () => {
|
|
41
|
+
const fake = startFakeModelLitellm({ masterKey: KEY });
|
|
42
|
+
const engine = stack(fake);
|
|
43
|
+
const at = (id: string): ModelProps => ({ id, model: 'xai/grok-4.7', modelName: 'grok' });
|
|
44
|
+
expect(await engine.deploy(declare(at('FAKE-id-a')))).toEqual({ Grok: 'create' });
|
|
45
|
+
fake.failNextReadBacks(1);
|
|
46
|
+
await expect(engine.deploy(declare(at('FAKE-id-b')))).rejects.toThrow(
|
|
47
|
+
/injected read-back failure/,
|
|
48
|
+
);
|
|
49
|
+
expect(fake.models().map(rowId)).toContain('FAKE-id-b');
|
|
50
|
+
// The row is this stack's own, posted before the read-back died. Without --adopt the resume
|
|
51
|
+
// still refuses; with it, the unfinished generation may take the row it created.
|
|
52
|
+
await expect(engine.deploy(declare(at('FAKE-id-b')))).rejects.toThrow(/--adopt/);
|
|
53
|
+
expect(await engine.deploy(declare(at('FAKE-id-b')), { adopt: true })).toEqual({
|
|
54
|
+
Grok: 'replace',
|
|
55
|
+
});
|
|
56
|
+
expect(await engine.deploy(declare(at('FAKE-id-b')), { adopt: true })).toEqual({ Grok: 'noop' });
|
|
57
|
+
});
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a `LiteLLM.Model` declares (props) and what is remembered about it (attributes).
|
|
3
|
+
*
|
|
4
|
+
* ⛔ NO CREDENTIAL VALUE IS A PROP OR AN ATTRIBUTE (S25). Alchemy persists props AND attributes
|
|
5
|
+
* unencrypted (`StateEncoding.ts` writes a `Redacted` value's inner string beside its tag,
|
|
6
|
+
* measured on alchemy 2.0.0-beta.79), so `apiKey` is `{ fromEnv: 'NAME' }`: the NAME is stored,
|
|
7
|
+
* the value lives only in the deploying process and on the wire, and it is sent in LiteLLM's own
|
|
8
|
+
* reference form `os.environ/NAME` — so the PROXY reads it from ITS environment at call time and
|
|
9
|
+
* the proxy's own DB row never carries a literal either. A `Redacted` prop would still land in
|
|
10
|
+
* state as plaintext (mcp-server-types.ts's reasoning, same store).
|
|
11
|
+
* ⛔ THE LIVE ROW'S `litellm_params` ARE NEVER MIRRORED INTO ATTRIBUTES. At v1.103.0 the read
|
|
12
|
+
* answers the stored params DECRYPTED but STRIPS `api_key` (measured on a live 1.103.0 proxy),
|
|
13
|
+
* and anything mirrored would land in state as plaintext — Alchemy persists attributes
|
|
14
|
+
* unencrypted. So a read compares only the visible fields the proxy returns, and this
|
|
15
|
+
* resource's own attributes carry a DIGEST of the DECLARED values (`paramsSeal`), never the
|
|
16
|
+
* values: that is how a plan notices a declared credential moved when the read cannot show it.
|
|
17
|
+
* ⚠️ NOT MODELLED, on purpose: the rest of `litellm_params` (rpm/tpm, timeouts, fallbacks,
|
|
18
|
+
* wildcard routing params, `mock_response`, vertex/aws credential blobs, …), cost fields on
|
|
19
|
+
* `model_info` beyond what the read returns, `teams`, and the config-file-only rows
|
|
20
|
+
* (`db_model: false`) — a reconcile that finds one REFUSES it (model-errors.ts): the DB
|
|
21
|
+
* API cannot manage what the proxy serves from its config file.
|
|
22
|
+
*/
|
|
23
|
+
import type { FromEnv } from '../secrets/write-only.ts';
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* The LiteLLM-SDK path of the deployment: a provider prefix, then the upstream model, such as
|
|
27
|
+
* `xai/grok-4.7` or `cloudflare/@cf/meta/llama-3.1-8b-instruct`. Required: LiteLLM needs it to
|
|
28
|
+
* pick the provider handler, and an unprefixed name is ambiguous.
|
|
29
|
+
*/
|
|
30
|
+
export type ModelLiteLLMPath = string;
|
|
31
|
+
|
|
32
|
+
export interface ModelProps {
|
|
33
|
+
/**
|
|
34
|
+
* The group name callers use (`/chat/completions` `model: …`), one group = one or more
|
|
35
|
+
* deployments. This is also how an existing row is ADOPTED: the live row whose `model_name`
|
|
36
|
+
* equals it. ⛔ Renaming a group changes nothing upstream — LiteLLM keys deployments by id —
|
|
37
|
+
* so a changed `modelName` with no pinned `id` is a REPLACE: the new group gets a fresh id, and
|
|
38
|
+
* the old row survives under the default `RemovalPolicy.retain()` (opt in to `destroy()` to
|
|
39
|
+
* delete it). A pinned `id` is that row: the same deployment is renamed in place
|
|
40
|
+
* (`patchBody` sends `model_name`), and keys routing to the old name miss.
|
|
41
|
+
*/
|
|
42
|
+
readonly modelName: string;
|
|
43
|
+
/**
|
|
44
|
+
* Pins the live row (adopts by id) or chooses the id a create asks for. Without it, a live row
|
|
45
|
+
* is found by `modelName` and a new one gets a deterministic physical name. A group name is
|
|
46
|
+
* shared by several deployments on a live proxy: one id selects exactly one.
|
|
47
|
+
*/
|
|
48
|
+
readonly id?: string;
|
|
49
|
+
/** The LiteLLM-SDK path, provider prefix included (`xai/grok-4.7`, `cloudflare/@cf/...`). */
|
|
50
|
+
readonly model: string;
|
|
51
|
+
/**
|
|
52
|
+
* The upstream base URL, when the deployment needs one. ⛔ Refused if it carries userinfo, a
|
|
53
|
+
* fragment or a secret-looking query parameter (`?token=…`): the URL is a prop, so it lands in
|
|
54
|
+
* state. Declare the credential as `apiKey` instead.
|
|
55
|
+
*/
|
|
56
|
+
readonly apiBase?: string;
|
|
57
|
+
/**
|
|
58
|
+
* The upstream credential, by the NAME of the environment variable that holds it — sent to the
|
|
59
|
+
* proxy as LiteLLM's own reference form `os.environ/NAME`, never a literal value. Omitted
|
|
60
|
+
* leaves the live credential exactly as the proxy holds it (an adopted row is never blanked).
|
|
61
|
+
*/
|
|
62
|
+
readonly apiKey?: FromEnv;
|
|
63
|
+
/** The deployment's capabilities, `mode` in LiteLLM's model_info — `chat`, `embedding`, …. */
|
|
64
|
+
readonly mode?: string;
|
|
65
|
+
/** The upstream model this one masquerades as, for cost/prompt mapping. */
|
|
66
|
+
readonly baseModel?: string;
|
|
67
|
+
/** Access groups this deployment belongs to. Always compared (as a set), default empty. */
|
|
68
|
+
readonly accessGroups?: readonly string[];
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export interface ModelAttributes {
|
|
72
|
+
readonly id: string;
|
|
73
|
+
readonly modelName: string;
|
|
74
|
+
/** Whether the row is served from the database (`model_info.db_model`); false = config-file row. */
|
|
75
|
+
readonly dbModel: boolean;
|
|
76
|
+
/** The provider-prefixed path as the live row carries it (null when the read omits it). */
|
|
77
|
+
readonly model: string | null;
|
|
78
|
+
readonly mode: string | null;
|
|
79
|
+
readonly baseModel: string | null;
|
|
80
|
+
readonly accessGroups: readonly string[];
|
|
81
|
+
/**
|
|
82
|
+
* Digest of the DECLARED params this write would send (`scrypt:<salt>:<digest>`), or `''`.
|
|
83
|
+
* ⛔ Never the values, never a digest of the LIVE row. This is how a plan notices that the
|
|
84
|
+
* environment variable behind `apiKey` rotated: the read strips `api_key`, so the seal is the
|
|
85
|
+
* only signal a declared credential moved (model-form.ts's `declaredDigest`).
|
|
86
|
+
*/
|
|
87
|
+
readonly paramsSeal: string;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** Whether a value is not a string with something in it. Takes `unknown`: a declaration can say anything. */
|
|
91
|
+
export const isBlank = (value: unknown): boolean =>
|
|
92
|
+
typeof value !== 'string' || value.trim() === '';
|
|
93
|
+
|
|
94
|
+
export const MODES: readonly string[] = [
|
|
95
|
+
'chat',
|
|
96
|
+
'completion',
|
|
97
|
+
'embedding',
|
|
98
|
+
'audio_transcription',
|
|
99
|
+
'audio_speech',
|
|
100
|
+
'image_generation',
|
|
101
|
+
'image_editing',
|
|
102
|
+
'moderation',
|
|
103
|
+
'rerank',
|
|
104
|
+
'search',
|
|
105
|
+
'realtime',
|
|
106
|
+
'batch',
|
|
107
|
+
'video',
|
|
108
|
+
'ocr',
|
|
109
|
+
];
|
|
110
|
+
|
|
111
|
+
/** Whether `model` carries a provider prefix, LiteLLM's `litellm.utils.get_llm_provider` rule. */
|
|
112
|
+
export const hasProviderPrefix = (model: string): boolean => /^[a-z0-9_-]+\//i.test(model);
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `LiteLLM.Model` through Alchemy's real Plan and Apply over the fake proxy
|
|
3
|
+
* (`fake-model-litellm.ts`): create, no-op, adopt and its stamping write, pinning, rename, drift.
|
|
4
|
+
*
|
|
5
|
+
* ★ EVERY VALUE IS `FAKE-*`. No environment variable is set anywhere: the resource sends
|
|
6
|
+
* LiteLLM's own reference form and never reads `process.env` (model-credential.ts), so there is
|
|
7
|
+
* no value to set and no value to leak — the test asserts exactly that.
|
|
8
|
+
* ⚠️ WHAT THE FAKE MODELS IS ITS OWN CHOICE, NOT A MEASUREMENT OF LITELLM 1.103.0 (see the fake).
|
|
9
|
+
* A test that leans on one of those choices says so.
|
|
10
|
+
*/
|
|
11
|
+
import { expect, test } from 'bun:test';
|
|
12
|
+
import * as Effect from 'effect/Effect';
|
|
13
|
+
import { FAKE_BASE } from './fake-litellm.ts';
|
|
14
|
+
import { type FakeModelLitellm, modelRow, startFakeModelLitellm } from './fake-model-litellm.ts';
|
|
15
|
+
import { fakeStack, writesOf } from './fake-stack.ts';
|
|
16
|
+
import { LiteLLMModel } from './model.ts';
|
|
17
|
+
import type { ModelProps } from './model-types.ts';
|
|
18
|
+
|
|
19
|
+
type Row = Record<string, unknown>;
|
|
20
|
+
|
|
21
|
+
const KEY = 'sk-test-master';
|
|
22
|
+
const stack = (fake: FakeModelLitellm) =>
|
|
23
|
+
fakeStack({ apiKey: KEY, baseUrl: FAKE_BASE }, fake.fetch);
|
|
24
|
+
const declare = (props: ModelProps, name = 'Grok') =>
|
|
25
|
+
Effect.gen(function* () {
|
|
26
|
+
yield* LiteLLMModel(name, props);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
const grok: ModelProps = {
|
|
30
|
+
apiKey: { fromEnv: 'FAKE_XAI_KEY' },
|
|
31
|
+
model: 'xai/grok-4.7',
|
|
32
|
+
modelName: 'grok',
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
test('a first create still reaches POST /model/new when the missing-id read is a 400', async () => {
|
|
36
|
+
const fake = startFakeModelLitellm({ masterKey: KEY });
|
|
37
|
+
expect(await stack(fake).deploy(declare(grok))).toEqual({ Grok: 'create' });
|
|
38
|
+
expect(writesOf(fake.requests())).toEqual(['POST /model/new']);
|
|
39
|
+
expect(fake.models()).toHaveLength(1);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test('creates a deployment that carries the reference credential, never a value', async () => {
|
|
43
|
+
const fake = startFakeModelLitellm({ masterKey: KEY });
|
|
44
|
+
expect(await stack(fake).deploy(declare(grok))).toEqual({ Grok: 'create' });
|
|
45
|
+
expect(fake.bodies()[0]).toMatchObject({
|
|
46
|
+
litellm_params: { api_key: 'os.environ/FAKE_XAI_KEY', model: 'xai/grok-4.7' },
|
|
47
|
+
model_info: { access_groups: [] },
|
|
48
|
+
model_name: 'grok',
|
|
49
|
+
});
|
|
50
|
+
// ★ a deterministic physical name, not a proxy-issued uuid
|
|
51
|
+
expect(String((fake.models()[0]?.['model_info'] as Row | undefined)?.['id'])).toMatch(
|
|
52
|
+
/^[a-z0-9-]+$/,
|
|
53
|
+
);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test('a second deploy of the same declaration writes nothing', async () => {
|
|
57
|
+
const fake = startFakeModelLitellm({ masterKey: KEY });
|
|
58
|
+
const same = stack(fake);
|
|
59
|
+
await same.deploy(declare(grok));
|
|
60
|
+
const before = fake.requests().length;
|
|
61
|
+
expect(await same.deploy(declare(grok))).toEqual({ Grok: 'noop' });
|
|
62
|
+
expect(writesOf(fake.requests().slice(before))).toEqual([]);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
test('a different environment NAME moves the reference; the value is never read', async () => {
|
|
66
|
+
const fake = startFakeModelLitellm({ masterKey: KEY });
|
|
67
|
+
const same = stack(fake);
|
|
68
|
+
await same.deploy(declare(grok));
|
|
69
|
+
const moved = { ...grok, apiKey: { fromEnv: 'FAKE_XAI_KEY_TWO' } };
|
|
70
|
+
expect(await same.deploy(declare(moved))).toEqual({ Grok: 'update' });
|
|
71
|
+
expect(fake.models()[0]?.['litellm_params']).toMatchObject({
|
|
72
|
+
api_key: 'os.environ/FAKE_XAI_KEY_TWO',
|
|
73
|
+
});
|
|
74
|
+
expect(await same.deploy(declare(moved))).toEqual({ Grok: 'noop' });
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
test('removing a declared api_base leaves the live row its own base', async () => {
|
|
78
|
+
const fake = startFakeModelLitellm({ masterKey: KEY });
|
|
79
|
+
const same = stack(fake);
|
|
80
|
+
const withBase = { ...grok, apiBase: 'https://api.xai.example.com' };
|
|
81
|
+
await same.deploy(declare(withBase));
|
|
82
|
+
// ★ the read cannot see api_base (it is never copied, model-form.ts), so it is the SEAL that
|
|
83
|
+
// notices the declaration changed — and the update deliberately sends no api_base.
|
|
84
|
+
expect(await same.deploy(declare(grok))).toEqual({ Grok: 'update' });
|
|
85
|
+
expect(fake.bodies().at(-1)?.['litellm_params']).toMatchObject({
|
|
86
|
+
api_key: 'os.environ/FAKE_XAI_KEY',
|
|
87
|
+
model: 'xai/grok-4.7',
|
|
88
|
+
});
|
|
89
|
+
expect(fake.bodies().at(-1)?.['litellm_params']).not.toHaveProperty('api_base');
|
|
90
|
+
expect(fake.models()[0]?.['litellm_params']).toMatchObject({
|
|
91
|
+
api_base: 'https://api.xai.example.com',
|
|
92
|
+
});
|
|
93
|
+
expect(await same.deploy(declare(grok))).toEqual({ Grok: 'noop' });
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
test('a live row is Unowned: refused without --adopt, adopted with no write when nothing differs', async () => {
|
|
97
|
+
const fake = startFakeModelLitellm({
|
|
98
|
+
masterKey: KEY,
|
|
99
|
+
seed: [
|
|
100
|
+
modelRow({
|
|
101
|
+
litellm_params: { model: 'xai/grok-4.7' },
|
|
102
|
+
model_info: { access_groups: ['FAKE-team'], id: 'FAKE-live-id', mode: 'chat' },
|
|
103
|
+
model_name: 'grok',
|
|
104
|
+
}),
|
|
105
|
+
],
|
|
106
|
+
});
|
|
107
|
+
const adopted: ModelProps = {
|
|
108
|
+
accessGroups: ['FAKE-team'],
|
|
109
|
+
model: 'xai/grok-4.7',
|
|
110
|
+
modelName: 'grok',
|
|
111
|
+
};
|
|
112
|
+
const engine = stack(fake);
|
|
113
|
+
await expect(engine.deploy(declare(adopted))).rejects.toThrow();
|
|
114
|
+
expect(writesOf(fake.requests())).toEqual([]);
|
|
115
|
+
expect(await engine.deploy(declare(adopted), { adopt: true })).toEqual({ Grok: 'adopted' });
|
|
116
|
+
// ★ A matching row records paramsSeal locally. The read strips `api_key`, so a same-shaped
|
|
117
|
+
// row could carry a DIFFERENT stored reference — but nothing was declared that manages an
|
|
118
|
+
// invisible param, and nothing else drifted, so no PATCH fires (model.ts).
|
|
119
|
+
expect(writesOf(fake.requests())).toEqual([]);
|
|
120
|
+
expect(fake.models()[0]?.['model_info'] as Row | undefined).toMatchObject({ mode: 'chat' });
|
|
121
|
+
expect(await engine.deploy(declare(adopted), { adopt: true })).toEqual({ Grok: 'noop' });
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
test('clearing groups reaches the PATCH route, the only write model_info supports', async () => {
|
|
125
|
+
// POST /model/update is never sent: v1.103.0 update_model rebuilds litellm_params and does not
|
|
126
|
+
// write model_info, so a fake that matched that would leave access_groups in place, and the
|
|
127
|
+
// read-back must not pass.
|
|
128
|
+
const fake = startFakeModelLitellm({
|
|
129
|
+
masterKey: KEY,
|
|
130
|
+
seed: [
|
|
131
|
+
modelRow({
|
|
132
|
+
litellm_params: { model: 'xai/grok-4.7' },
|
|
133
|
+
model_info: { access_groups: ['FAKE-team'], id: 'FAKE-live-id' },
|
|
134
|
+
model_name: 'grok',
|
|
135
|
+
}),
|
|
136
|
+
],
|
|
137
|
+
});
|
|
138
|
+
const adopted: ModelProps = { model: 'xai/grok-4.7', modelName: 'grok' };
|
|
139
|
+
expect(await stack(fake).deploy(declare(adopted), { adopt: true })).toEqual({ Grok: 'adopted' });
|
|
140
|
+
const id = String((fake.models()[0]?.['model_info'] as Row | undefined)?.['id']);
|
|
141
|
+
expect(writesOf(fake.requests())).toContain(`PATCH /model/${id}/update`);
|
|
142
|
+
expect(fake.models()[0]?.['model_info'] as Row | undefined).toMatchObject({ access_groups: [] });
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
test('adopting a row whose groups the declaration omits clears them', async () => {
|
|
146
|
+
const fake = startFakeModelLitellm({
|
|
147
|
+
masterKey: KEY,
|
|
148
|
+
seed: [
|
|
149
|
+
modelRow({
|
|
150
|
+
litellm_params: { model: 'xai/grok-4.7' },
|
|
151
|
+
model_info: { access_groups: ['FAKE-team'], id: 'FAKE-live-id' },
|
|
152
|
+
model_name: 'grok',
|
|
153
|
+
}),
|
|
154
|
+
],
|
|
155
|
+
});
|
|
156
|
+
const adopted: ModelProps = { model: 'xai/grok-4.7', modelName: 'grok' };
|
|
157
|
+
expect(await stack(fake).deploy(declare(adopted), { adopt: true })).toEqual({ Grok: 'adopted' });
|
|
158
|
+
// ★ access_groups is always managed with a default empty set (model-types.ts)
|
|
159
|
+
expect(fake.models()[0]?.['model_info'] as Row | undefined).toMatchObject({ access_groups: [] });
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
test('a proxy that drops an edit it cannot apply fails the deploy instead of claiming success', async () => {
|
|
163
|
+
// ⚠️ the fake's own model of a truthiness check on the update route — unmeasured at 1.103.0
|
|
164
|
+
const fake = startFakeModelLitellm({
|
|
165
|
+
editIgnoresFalsy: true,
|
|
166
|
+
masterKey: KEY,
|
|
167
|
+
seed: [
|
|
168
|
+
modelRow({
|
|
169
|
+
litellm_params: { model: 'xai/grok-4.7' },
|
|
170
|
+
model_info: { access_groups: ['FAKE-team'], id: 'FAKE-live-id' },
|
|
171
|
+
model_name: 'grok',
|
|
172
|
+
}),
|
|
173
|
+
],
|
|
174
|
+
});
|
|
175
|
+
const adopted: ModelProps = { model: 'xai/grok-4.7', modelName: 'grok' };
|
|
176
|
+
await expect(stack(fake).deploy(declare(adopted), { adopt: true })).rejects.toThrow();
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
test('the read strips api_key; the seal, not the read, proves convergence', async () => {
|
|
180
|
+
const fake = startFakeModelLitellm({ masterKey: KEY });
|
|
181
|
+
const same = stack(fake);
|
|
182
|
+
await same.deploy(declare(grok));
|
|
183
|
+
// ★ measured at v1.103.0: the read answers params decrypted but strips `api_key` (the fake
|
|
184
|
+
// models exactly that), while the stored row keeps the reference — the wire, not the table.
|
|
185
|
+
const read = (await (
|
|
186
|
+
await fake.fetch(`${FAKE_BASE}/model/info`, {
|
|
187
|
+
headers: { authorization: `Bearer ${KEY}` },
|
|
188
|
+
})
|
|
189
|
+
).json()) as { data: readonly Row[] };
|
|
190
|
+
expect(read.data[0]?.['litellm_params']).toEqual({ model: 'xai/grok-4.7' });
|
|
191
|
+
expect(fake.models()[0]?.['litellm_params']).toMatchObject({
|
|
192
|
+
api_key: 'os.environ/FAKE_XAI_KEY',
|
|
193
|
+
});
|
|
194
|
+
// The read can never carry the credential, so a matching seal is what makes this a noop.
|
|
195
|
+
const before = fake.requests().length;
|
|
196
|
+
expect(await same.deploy(declare(grok))).toEqual({ Grok: 'noop' });
|
|
197
|
+
expect(writesOf(fake.requests().slice(before))).toEqual([]);
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
test('a row the list omits is still adopted through the by-id read', async () => {
|
|
201
|
+
const fake = startFakeModelLitellm({
|
|
202
|
+
listOmits: ['FAKE-live-id'],
|
|
203
|
+
masterKey: KEY,
|
|
204
|
+
seed: [
|
|
205
|
+
modelRow({
|
|
206
|
+
litellm_params: { model: 'xai/grok-4.7' },
|
|
207
|
+
model_info: { access_groups: [], id: 'FAKE-live-id' },
|
|
208
|
+
model_name: 'grok',
|
|
209
|
+
}),
|
|
210
|
+
],
|
|
211
|
+
});
|
|
212
|
+
const pinned: ModelProps = { ...grok, id: 'FAKE-live-id' };
|
|
213
|
+
expect(await stack(fake).deploy(declare(pinned), { adopt: true })).toEqual({ Grok: 'adopted' });
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
test('a declaration carrying a credential value is refused before a single request', async () => {
|
|
217
|
+
const fake = startFakeModelLitellm({ masterKey: KEY });
|
|
218
|
+
await expect(
|
|
219
|
+
stack(fake).deploy(declare({ ...grok, apiKey: 'FAKE-literal-value' as never })),
|
|
220
|
+
).rejects.toThrow();
|
|
221
|
+
expect(fake.requests()).toEqual([]);
|
|
222
|
+
});
|