@astrifer-ai/agent-os-management
v0.1.0
Published
TypeScript SDK for Astrifer Agent OS tenant management.
Downloads
29
Readme
Astrifer Agent OS Management SDK
Typed enterprise Tenant Management SDK for Astrifer Agent OS.
npm install @astrifer-ai/agent-os-managementCurrent source targets Tenant Management OpenAPI contract 0.21.0; the
initial package version is 0.1.0.
CONTRACT_VERSION is the Tenant Management document version. The HTTP
x-ariadra-api-version header is still the shared platform-v1 transport
version until the platform adds a dedicated Tenant Management negotiation
header.
Use @astrifer-ai/agent-os-management with an ariadra_mgmt_* API key for
tenant-scoped automation:
- member list/create
- namespace create/list/update
- tenant-management API key issue/list/revoke
- LLM provider credential create/list/get/delete/refresh and credential-scoped exact-model listing
- Event Bus adapter installation lifecycle, Runtime grants, controlled subscription teardown, and short-lived Link Authorization issuance
Use @astrifer-ai/agent-os for API-key data-plane workflows such as sessions, events,
Volume, AgentSpec/EnvironmentSpec, and GET /v1/llm-provider-credentials
session credential discovery.
import { AgentOSManagement } from "@astrifer-ai/agent-os-management";
const management = new AgentOSManagement({
apiKey: "ariadra_mgmt_...",
baseURL: process.env.ARIADRA_BASE_URL!,
maxRetries: 2, // opt in to transient retries for eligible requests
});
const keys = await management.apiKeys.list();
const models = await management.llmProviderCredentials.models.list("cred_...", {
runtime_driver: "codex_cli",
});
await management.llmProviderCredentials.refresh("cred_...");Event Bus control-plane operations live under
management.eventBus.adapterInstallations. Installation, grant, and lifecycle
mutations carry a caller-generated operation_id; the SDK marks these commands
as safe for transport retry when maxRetries > 0, while preserving the exact
request body.
const installation = await management.eventBus.adapterInstallations.create({
operation_id: "install_01K...",
connector_kind: "slack",
metadata: {},
initial_grant: {
subject_kind: "service_principal",
subject_id: "spr_01K...",
permissions: ["event_bus.subscribe", "event_bus.delivery.ack"],
namespace_ids: ["default"],
},
});
const authorization =
await management.eventBus.adapterInstallations.linkAuthorizations.issue(
installation.installation.adapter_installation_id,
{
operation_id: "link_01K...",
action: "link",
authorized_subject_kind: "service_principal",
authorized_subject_id: "spr_01K...",
},
);
if (authorization.data.replayed) {
// The original bearer handle is intentionally unavailable. Start a new
// issue operation with a new operation_id if the first response was lost.
throw new Error("Link Authorization was replayed without its secret handle");
}
const authorizationHandle = authorization.data.authorization_handle;
let afterSubscriptionId: string | undefined;
for (;;) {
const page =
await management.eventBus.adapterInstallations.subscriptions.list(
installation.installation.adapter_installation_id,
{
limit: 50,
...(afterSubscriptionId === undefined
? {}
: { after_subscription_id: afterSubscriptionId }),
},
);
for (const subscription of page.data) {
const receipt =
await management.eventBus.adapterInstallations.subscriptions.deprovision(
installation.installation.adapter_installation_id,
subscription.subscription_id,
{
force_discard: false,
operation_id: `inspect-${subscription.subscription_id}`,
reason: "retire connector installation",
},
);
if (receipt.needs_force_discard) {
// A destructive follow-up requires explicit operator approval and a new
// operation_id. Do not silently promote this request to force_discard.
}
}
if (!page.has_more) break;
if (page.next_after_subscription_id === null) {
throw new Error("subscription page omitted its continuation cursor");
}
afterSubscriptionId = page.next_after_subscription_id;
}Typed grant subjects pair service_principal with an spr_* ID or
data_plane_api_key with an ak_* ID. Tenant Management 0.17 removes the
deprecated { api_key_id: "ak_*" } grant and no-subject Link Authorization
shapes; every request and response now uses an exact typed subject.
Installation archive is allowed only after every owned subscription reaches
deprovisioned. A force_discard: true teardown is destructive and audited.
With maxRetries > 0, the SDK can safely retry an operation-ID-backed
deprovision request without changing its intent. Applications must still use
subscriptions.list(...) to observe current state because a replay returns the
original immutable receipt. Always exhaust all list pages before attempting to
archive an installation.
The Link Authorization handle is a short-lived bearer secret returned only in
the first successful response. The SDK never automatically retries this issue
request: a same-operation replay returns replayed: true and omits the handle.
Do not log or persist the handle beyond the connector action that consumes it.
The package does not include UserJWT /v1/auth/* or /v1/users/me/* flows,
staff /v1/admin/* endpoints, platform plan-tier administration, global audit
views, Event Bus data-plane delivery/binding/inbound operations, or platform
model catalog mutation.
The package owns its client and resource wrappers under src/, while reusing
only package-neutral transport primitives from the repository's
internal/sdk-core directory. Builds bundle those primitives, so the published
package is self-contained and does not depend on @astrifer-ai/agent-os.
await management.members.create({
email: "[email protected]",
password: "temporary-password",
role: "admin",
});For newly added management endpoints that do not have typed wrappers yet, use
the low-level request escape hatch. The escape hatch is intentionally restricted
to /v1/tenant/* paths:
const result = await management.request({
method: "GET",
path: "/v1/tenant/api-keys",
});Curated methods apply generated public input limits before transport and throw
InputValidationError with a stable field path, unit, limit, and reason. The
error never contains the submitted value, API key, provider secret, token, or
raw server error. Inputs are rejected rather than truncated or normalized.
management.request(...) deliberately bypasses this SDK preflight; it remains
path-restricted, and the Platform is always the final validation authority.
When using both @astrifer-ai/agent-os and @astrifer-ai/agent-os-management in the same
app, prefer isAgentOSError(err) / isHasOpenTurnError(err) over
cross-package instanceof APIError checks. The two packages bundle their own
copy of the error classes; the helper functions use a global symbol marker and
work across packages.
