antpath 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,67 +1,66 @@
1
- ---
2
- title: antpath
3
- ---
4
-
5
- # antpath
6
-
7
- antpath is a TypeScript-first SDK for running autonomous Claude Managed Agents sessions from code-defined, secret-free Templates.
8
-
9
- ## MVP boundaries
10
-
11
- - SDK-only.
12
- - Claude Managed Agents only.
13
- - Caller-held provider key.
14
- - No stored provider keys, MCP credentials, or output file contents.
15
- - Manual cleanup by default.
16
-
17
- ## Quickstart
18
-
19
- ```ts
20
- import { AntpathClient, defineTemplate, string } from "antpath";
21
-
22
- const client = new AntpathClient({
23
- anthropicApiKey: process.env.ANTHROPIC_API_KEY
24
- });
25
-
26
- const template = defineTemplate({
27
- name: "hello",
28
- model: "claude-haiku-4-5",
29
- system: "You are a concise automation agent.",
30
- messages: ["Write a short answer about {{topic}}."],
31
- variables: {
32
- topic: string()
33
- }
34
- });
35
-
36
- const handle = await client.run(template, {
37
- variables: { topic: "test-first SDK design" }
38
- });
39
-
40
- const result = await handle.wait();
41
- console.log(result.status, await handle.usage());
42
- await handle.downloadOutputs("./outputs");
43
- await handle.cleanup();
44
- ```
45
-
46
- ## Test commands
47
-
48
- ```text
49
- npm run test:unit
50
- npm run test:integration:components
51
- npm run test:integration:api
52
- npm run test:e2e:live
53
- ```
54
-
55
- Live e2e tests require `.env.local` and `RUN_LIVE_ANTPATH_TESTS=1`.
56
-
57
- ## Guides
58
-
59
- - [Quickstart](docs/quickstart.md)
60
- - [Templates](docs/templates.md)
61
- - [Credentials](docs/credentials.md)
62
- - [MCP](docs/mcp.md)
63
- - [Skills](docs/skills.md)
64
- - [Outputs](docs/outputs.md)
65
- - [Cleanup](docs/cleanup.md)
66
- - [Testing](docs/testing.md)
67
- - [Release](docs/release.md)
1
+ ---
2
+ title: antpath
3
+ ---
4
+
5
+ # antpath
6
+
7
+ antpath is a TypeScript-first SDK for running autonomous Claude Managed Agents sessions from code-defined, secret-free Templates.
8
+
9
+ ## MVP boundaries
10
+
11
+ - SDK-only.
12
+ - Claude Managed Agents only.
13
+ - Caller-held provider key.
14
+ - No stored provider keys, MCP credentials, or output file contents.
15
+ - Manual cleanup by default.
16
+
17
+ ## Quickstart
18
+
19
+ ```ts
20
+ import { AntpathClient, defineTemplate, string } from "antpath";
21
+
22
+ const client = new AntpathClient({
23
+ anthropicApiKey: process.env.ANTHROPIC_API_KEY
24
+ });
25
+
26
+ const template = defineTemplate({
27
+ name: "hello",
28
+ model: "claude-haiku-4-5",
29
+ system: "You are a concise automation agent.",
30
+ messages: ["Write a short answer about {{topic}}."],
31
+ variables: {
32
+ topic: string()
33
+ }
34
+ });
35
+
36
+ const handle = await client.run(template, {
37
+ variables: { topic: "test-first SDK design" }
38
+ });
39
+
40
+ const result = await handle.wait();
41
+ console.log(result.status, await handle.usage());
42
+ await handle.downloadOutputs("./outputs");
43
+ await handle.cleanup();
44
+ ```
45
+
46
+ ## Test commands
47
+
48
+ ```text
49
+ npm run test:unit
50
+ npm run test:unit:recorded
51
+ npm run test:e2e:live
52
+ ```
53
+
54
+ Unit tests are deterministic and may use fakes or sanitized recorded snapshots. Live e2e tests run when `pnpm test:e2e:live` is invoked with `.env.local` containing `ANTHROPIC_API_KEY`.
55
+
56
+ ## Guides
57
+
58
+ - [Quickstart](docs/quickstart.md)
59
+ - [Templates](docs/templates.md)
60
+ - [Credentials](docs/credentials.md)
61
+ - [MCP](docs/mcp.md)
62
+ - [Skills](docs/skills.md)
63
+ - [Outputs](docs/outputs.md)
64
+ - [Cleanup](docs/cleanup.md)
65
+ - [Testing](docs/testing.md)
66
+ - [Release](docs/release.md)
@@ -2,9 +2,12 @@ import { CredentialValidationError } from "./errors.js";
2
2
  export function validateCredentials(template, credentials = {}) {
3
3
  for (const [key, requirement] of Object.entries(template.credentialRequirements)) {
4
4
  const credential = credentials[key];
5
- if (!credential) {
5
+ if (credential === undefined) {
6
6
  throw new CredentialValidationError(`Missing credential for MCP server '${key}'`);
7
7
  }
8
+ if (!isRecord(credential)) {
9
+ throw new CredentialValidationError(`Credential for MCP server '${key}' must be an object`);
10
+ }
8
11
  if (credential.type !== requirement.type) {
9
12
  throw new CredentialValidationError(`Credential for MCP server '${key}' must be '${requirement.type}'`);
10
13
  }
@@ -17,11 +20,37 @@ export function validateCredentials(template, credentials = {}) {
17
20
  }
18
21
  }
19
22
  function validateCredentialValue(key, credential) {
20
- if (credential.type === "static_bearer" && !credential.token) {
21
- throw new CredentialValidationError(`Static bearer credential for '${key}' requires token`);
23
+ if (!isRecord(credential)) {
24
+ throw new CredentialValidationError(`Credential for MCP server '${key}' must be an object`);
25
+ }
26
+ if (credential.type === "static_bearer") {
27
+ assertAllowedFields(key, credential, ["type", "token"]);
28
+ if (typeof credential.token !== "string" || credential.token.length === 0) {
29
+ throw new CredentialValidationError(`Static bearer credential for '${key}' requires token`);
30
+ }
31
+ return;
22
32
  }
23
- if (credential.type === "oauth_access_token" && !credential.accessToken) {
24
- throw new CredentialValidationError(`OAuth credential for '${key}' requires accessToken`);
33
+ if (credential.type === "oauth_access_token") {
34
+ assertAllowedFields(key, credential, ["type", "accessToken", "expiresAt"]);
35
+ if (typeof credential.accessToken !== "string" || credential.accessToken.length === 0) {
36
+ throw new CredentialValidationError(`OAuth credential for '${key}' requires accessToken`);
37
+ }
38
+ if (credential.expiresAt !== undefined && (typeof credential.expiresAt !== "string" || credential.expiresAt.length === 0)) {
39
+ throw new CredentialValidationError(`OAuth credential for '${key}' has invalid expiresAt`);
40
+ }
41
+ return;
25
42
  }
43
+ throw new CredentialValidationError(`Credential for MCP server '${key}' has unsupported type`);
44
+ }
45
+ function assertAllowedFields(key, credential, allowed) {
46
+ const allowedSet = new Set(allowed);
47
+ for (const field of Object.keys(credential)) {
48
+ if (!allowedSet.has(field)) {
49
+ throw new CredentialValidationError(`Credential for MCP server '${key}' contains unsupported field '${field}'`);
50
+ }
51
+ }
52
+ }
53
+ function isRecord(input) {
54
+ return typeof input === "object" && input !== null && !Array.isArray(input);
26
55
  }
27
56
  //# sourceMappingURL=credentials.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"credentials.js","sourceRoot":"","sources":["../src/credentials.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC;AAIxD,MAAM,UAAU,mBAAmB,CAAC,QAA0B,EAAE,cAA+C,EAAE;IAC/G,KAAK,MAAM,CAAC,GAAG,EAAE,WAAW,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAC,EAAE,CAAC;QACjF,MAAM,UAAU,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;QACpC,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,MAAM,IAAI,yBAAyB,CAAC,sCAAsC,GAAG,GAAG,CAAC,CAAC;QACpF,CAAC;QACD,IAAI,UAAU,CAAC,IAAI,KAAK,WAAW,CAAC,IAAI,EAAE,CAAC;YACzC,MAAM,IAAI,yBAAyB,CAAC,8BAA8B,GAAG,cAAc,WAAW,CAAC,IAAI,GAAG,CAAC,CAAC;QAC1G,CAAC;QACD,uBAAuB,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;IAC3C,CAAC;IACD,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;QAC3C,IAAI,CAAC,QAAQ,CAAC,sBAAsB,CAAC,GAAG,CAAC,EAAE,CAAC;YAC1C,MAAM,IAAI,yBAAyB,CAAC,+CAA+C,GAAG,GAAG,CAAC,CAAC;QAC7F,CAAC;IACH,CAAC;AACH,CAAC;AAED,SAAS,uBAAuB,CAAC,GAAW,EAAE,UAA2B;IACvE,IAAI,UAAU,CAAC,IAAI,KAAK,eAAe,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;QAC7D,MAAM,IAAI,yBAAyB,CAAC,iCAAiC,GAAG,kBAAkB,CAAC,CAAC;IAC9F,CAAC;IACD,IAAI,UAAU,CAAC,IAAI,KAAK,oBAAoB,IAAI,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC;QACxE,MAAM,IAAI,yBAAyB,CAAC,yBAAyB,GAAG,wBAAwB,CAAC,CAAC;IAC5F,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"credentials.js","sourceRoot":"","sources":["../src/credentials.ts"],"names":[],"mappings":"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"}
@@ -11,8 +11,16 @@ export async function downloadOutputs(provider, sessionId, options) {
11
11
  throw new Error(`Refusing to download ${totalBytes} bytes; maxTotalBytes exceeded`);
12
12
  }
13
13
  const manifest = { directory: options.directory, files: [] };
14
+ let downloadedBytes = 0;
14
15
  for (const file of files) {
15
16
  const content = await provider.downloadFile(file.id);
17
+ if (file.sizeBytes !== undefined && content.byteLength !== file.sizeBytes) {
18
+ throw new Error(`Downloaded byte size for ${file.id} did not match provider metadata`);
19
+ }
20
+ downloadedBytes += content.byteLength;
21
+ if (downloadedBytes > (options.maxTotalBytes ?? DEFAULT_MAX_BYTES)) {
22
+ throw new Error(`Downloaded outputs exceeded maxTotalBytes`);
23
+ }
16
24
  const localPath = await writeFileSafe(options.directory, file.filename, content);
17
25
  const entry = {
18
26
  providerFileId: file.id,
@@ -1 +1 @@
1
- {"version":3,"file":"downloader.js","sourceRoot":"","sources":["../../src/files/downloader.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAElD,MAAM,iBAAiB,GAAG,GAAG,CAAC;AAC9B,MAAM,iBAAiB,GAAG,GAAG,GAAG,IAAI,GAAG,IAAI,CAAC;AAE5C,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,QAA8B,EAC9B,SAAiB,EACjB,OAA+B;IAE/B,MAAM,KAAK,GAAG,WAAW,CAAC,MAAM,QAAQ,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC,CAAC;IACxE,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,OAAO,CAAC,QAAQ,IAAI,iBAAiB,CAAC,EAAE,CAAC;QAC3D,MAAM,IAAI,KAAK,CAAC,wBAAwB,KAAK,CAAC,MAAM,2BAA2B,CAAC,CAAC;IACnF,CAAC;IACD,MAAM,UAAU,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,IAAI,CAAC,SAAS,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC/E,IAAI,UAAU,GAAG,CAAC,OAAO,CAAC,aAAa,IAAI,iBAAiB,CAAC,EAAE,CAAC;QAC9D,MAAM,IAAI,KAAK,CAAC,wBAAwB,UAAU,gCAAgC,CAAC,CAAC;IACtF,CAAC;IACD,MAAM,QAAQ,GAAG,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,KAAK,EAAE,EAAgD,EAAE,CAAC;IAC3G,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACrD,MAAM,SAAS,GAAG,MAAM,aAAa,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QACjF,MAAM,KAAK,GAAG;YACZ,cAAc,EAAE,IAAI,CAAC,EAAE;YACvB,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,SAAS;SACV,CAAC;QACF,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,KAAK,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;IACtG,CAAC;IACD,OAAO,EAAE,QAAQ,EAAE,CAAC;AACtB,CAAC;AAED,SAAS,WAAW,CAAC,KAAqB,EAAE,OAA+B;IACzE,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;QACrB,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,OAAO,CAAC,OAAO,YAAY,MAAM,EAAE,CAAC;QACtC,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,YAAY,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC1G,CAAC;IACD,OAAO,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;AACvC,CAAC"}
1
+ {"version":3,"file":"downloader.js","sourceRoot":"","sources":["../../src/files/downloader.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,5 +1,9 @@
1
1
  export { AntpathClient } from "./client.js";
2
+ export { AntpathPlatformClient, PlatformApiError } from "./platform/index.js";
3
+ export { AnthropicManagedAgentsProvider } from "./providers/anthropic/provider.js";
4
+ export type { ManagedAgentProvider, ProviderSkillRef, SessionResourceInput, UploadFileInput } from "./providers/types.js";
5
+ export type { PlatformEvent, PlatformOutput, PlatformRun, SignedOutputLink } from "./platform/index.js";
2
6
  export { compileTemplate, defineTemplate, requiredOAuthAccessToken, requiredStaticBearer, string, type TemplateDefinition, type TemplateVariableDefinition } from "./template/index.js";
3
- export type { CleanupPolicy, CredentialInput, DownloadOutputsOptions, DownloadOutputsResult, Logger, OutputManifest, RunEvent, RunHandle, RunOptions, RunResult, RunStatus, UsageSummary } from "./types.js";
7
+ export type { CleanupPolicy, CleanupResult, CredentialInput, DownloadOutputsOptions, DownloadOutputsResult, Logger, OutputManifest, ProviderEvent, ProviderFile, ProviderResourceIds, RunEvent, RunHandle, RunOptions, RunResult, RunStatus, UsageSummary } from "./types.js";
4
8
  export { SecretString, redactSecrets } from "./utils/secrets.js";
5
9
  export { AntpathError, CleanupError, CredentialValidationError, ProviderError, RunStateError, TemplateValidationError } from "./errors.js";
package/dist/index.js CHANGED
@@ -1,4 +1,6 @@
1
1
  export { AntpathClient } from "./client.js";
2
+ export { AntpathPlatformClient, PlatformApiError } from "./platform/index.js";
3
+ export { AnthropicManagedAgentsProvider } from "./providers/anthropic/provider.js";
2
4
  export { compileTemplate, defineTemplate, requiredOAuthAccessToken, requiredStaticBearer, string } from "./template/index.js";
3
5
  export { SecretString, redactSecrets } from "./utils/secrets.js";
4
6
  export { AntpathError, CleanupError, CredentialValidationError, ProviderError, RunStateError, TemplateValidationError } from "./errors.js";
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EACL,eAAe,EACf,cAAc,EACd,wBAAwB,EACxB,oBAAoB,EACpB,MAAM,EAGP,MAAM,qBAAqB,CAAC;AAe7B,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACjE,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,yBAAyB,EACzB,aAAa,EACb,aAAa,EACb,uBAAuB,EACxB,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC9E,OAAO,EAAE,8BAA8B,EAAE,MAAM,mCAAmC,CAAC;AAGnF,OAAO,EACL,eAAe,EACf,cAAc,EACd,wBAAwB,EACxB,oBAAoB,EACpB,MAAM,EAGP,MAAM,qBAAqB,CAAC;AAmB7B,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACjE,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,yBAAyB,EACzB,aAAa,EACb,aAAa,EACb,uBAAuB,EACxB,MAAM,aAAa,CAAC"}
@@ -0,0 +1,73 @@
1
+ type FetchLike = (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
2
+ export type PlatformJsonPrimitive = string | number | boolean | null;
3
+ export type PlatformJsonValue = PlatformJsonPrimitive | readonly PlatformJsonValue[] | {
4
+ readonly [key: string]: PlatformJsonValue;
5
+ };
6
+ export interface PlatformTemplateSubmission {
7
+ readonly name: string;
8
+ readonly model: string;
9
+ readonly templateHash: string;
10
+ readonly system?: string;
11
+ readonly messages: readonly string[];
12
+ readonly metadata?: Record<string, PlatformJsonValue>;
13
+ }
14
+ export interface PlatformOutputPolicy {
15
+ readonly capture: boolean;
16
+ readonly globs?: readonly string[];
17
+ }
18
+ export type PlatformClaudeSessionCleanup = "retain" | "delete";
19
+ export interface PlatformCleanupPolicy {
20
+ readonly claudeSession?: PlatformClaudeSessionCleanup;
21
+ }
22
+ export interface PlatformRunSubmissionRequest {
23
+ readonly workspaceId: string;
24
+ readonly providerConnectionId: string;
25
+ readonly idempotencyKey: string;
26
+ readonly template: PlatformTemplateSubmission;
27
+ readonly variables?: Record<string, PlatformJsonValue>;
28
+ readonly credentialReferences?: Record<string, string>;
29
+ readonly output?: PlatformOutputPolicy;
30
+ readonly cleanup?: PlatformCleanupPolicy;
31
+ }
32
+ export interface AntpathPlatformClientOptions {
33
+ readonly baseUrl: string;
34
+ readonly apiToken: string;
35
+ readonly fetch?: FetchLike;
36
+ }
37
+ export interface PlatformRun {
38
+ readonly id: string;
39
+ readonly status: string;
40
+ readonly [key: string]: unknown;
41
+ }
42
+ export interface PlatformEvent {
43
+ readonly id: string;
44
+ readonly [key: string]: unknown;
45
+ }
46
+ export interface PlatformOutput {
47
+ readonly id: string;
48
+ readonly [key: string]: unknown;
49
+ }
50
+ export interface SignedOutputLink {
51
+ readonly url: string;
52
+ readonly [key: string]: unknown;
53
+ }
54
+ export declare class PlatformApiError extends Error {
55
+ readonly status: number;
56
+ readonly details: unknown;
57
+ constructor(status: number, message: string, details: unknown);
58
+ }
59
+ export declare class AntpathPlatformClient {
60
+ private readonly baseUrl;
61
+ private readonly apiToken;
62
+ private readonly fetchImpl;
63
+ constructor(options: AntpathPlatformClientOptions);
64
+ submitRun(request: PlatformRunSubmissionRequest): Promise<PlatformRun>;
65
+ getRun(workspaceId: string, runId: string): Promise<PlatformRun>;
66
+ listRunEvents(workspaceId: string, runId: string): Promise<readonly PlatformEvent[]>;
67
+ listOutputs(workspaceId: string, runId: string): Promise<readonly PlatformOutput[]>;
68
+ createOutputLink(workspaceId: string, runId: string, outputId: string): Promise<SignedOutputLink>;
69
+ cancelRun(workspaceId: string, runId: string): Promise<void>;
70
+ deleteRun(workspaceId: string, runId: string): Promise<void>;
71
+ private request;
72
+ }
73
+ export {};
@@ -0,0 +1,107 @@
1
+ export class PlatformApiError extends Error {
2
+ status;
3
+ details;
4
+ constructor(status, message, details) {
5
+ super(message);
6
+ this.name = "PlatformApiError";
7
+ this.status = status;
8
+ this.details = details;
9
+ }
10
+ }
11
+ export class AntpathPlatformClient {
12
+ baseUrl;
13
+ apiToken;
14
+ fetchImpl;
15
+ constructor(options) {
16
+ const record = options;
17
+ if ("anthropicApiKey" in record || "providerApiKey" in record) {
18
+ throw new Error("Platform client does not accept provider keys");
19
+ }
20
+ if (!options.apiToken) {
21
+ throw new Error("apiToken is required");
22
+ }
23
+ this.baseUrl = new URL(options.baseUrl.endsWith("/") ? options.baseUrl : `${options.baseUrl}/`);
24
+ this.apiToken = options.apiToken;
25
+ this.fetchImpl = options.fetch ?? fetch;
26
+ }
27
+ async submitRun(request) {
28
+ return this.request("/api/runs", {
29
+ method: "POST",
30
+ body: JSON.stringify(request)
31
+ });
32
+ }
33
+ async getRun(workspaceId, runId) {
34
+ const response = await this.request(`/api/runs/${encodeURIComponent(runId)}`, {}, { workspaceId });
35
+ return hasRun(response) ? response.run : response;
36
+ }
37
+ async listRunEvents(workspaceId, runId) {
38
+ const response = await this.request(`/api/runs/${encodeURIComponent(runId)}/events`, {}, { workspaceId });
39
+ return response.events;
40
+ }
41
+ async listOutputs(workspaceId, runId) {
42
+ const response = await this.request(`/api/runs/${encodeURIComponent(runId)}/outputs`, {}, { workspaceId });
43
+ return response.outputs;
44
+ }
45
+ async createOutputLink(workspaceId, runId, outputId) {
46
+ return this.request(`/api/runs/${encodeURIComponent(runId)}/outputs/${encodeURIComponent(outputId)}/link`, { method: "POST" }, { workspaceId });
47
+ }
48
+ async cancelRun(workspaceId, runId) {
49
+ await this.request(`/api/runs/${encodeURIComponent(runId)}/cancel`, { method: "POST" }, { workspaceId });
50
+ }
51
+ async deleteRun(workspaceId, runId) {
52
+ await this.request(`/api/runs/${encodeURIComponent(runId)}`, { method: "DELETE" }, { workspaceId });
53
+ }
54
+ async request(path, init = {}, query = {}) {
55
+ const url = new URL(path.replace(/^\//, ""), this.baseUrl);
56
+ for (const [key, value] of Object.entries(query)) {
57
+ url.searchParams.set(key, value);
58
+ }
59
+ const headers = {
60
+ accept: "application/json",
61
+ ...(init.body ? { "content-type": "application/json" } : {}),
62
+ authorization: `Bearer ${this.apiToken}`,
63
+ ...normalizeHeaders(init.headers)
64
+ };
65
+ const response = await this.fetchImpl(url, { ...init, headers });
66
+ const body = await readJson(response);
67
+ if (!response.ok) {
68
+ throw new PlatformApiError(response.status, extractErrorMessage(body), body);
69
+ }
70
+ return body;
71
+ }
72
+ }
73
+ function normalizeHeaders(headers) {
74
+ if (!headers) {
75
+ return {};
76
+ }
77
+ if (headers instanceof Headers) {
78
+ return Object.fromEntries(headers.entries());
79
+ }
80
+ if (Array.isArray(headers)) {
81
+ return Object.fromEntries(headers);
82
+ }
83
+ return headers;
84
+ }
85
+ async function readJson(response) {
86
+ const text = await response.text();
87
+ if (text.length === 0) {
88
+ return {};
89
+ }
90
+ return JSON.parse(text);
91
+ }
92
+ function extractErrorMessage(body) {
93
+ if (body && typeof body === "object" && "error" in body) {
94
+ const error = body.error;
95
+ if (error && typeof error === "object" && "message" in error) {
96
+ const message = error.message;
97
+ if (typeof message === "string") {
98
+ return message;
99
+ }
100
+ }
101
+ }
102
+ return "Platform request failed";
103
+ }
104
+ function hasRun(input) {
105
+ return Boolean(input && typeof input === "object" && "run" in input);
106
+ }
107
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/platform/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export * from "./client.js";
@@ -0,0 +1,2 @@
1
+ export * from "./client.js";
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/platform/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC"}
@@ -3,10 +3,16 @@ import { SecretString } from "../../utils/secrets.js";
3
3
  import type { ResolvedTemplate } from "../../template/compiler.js";
4
4
  import type { CleanupResult } from "../../types.js";
5
5
  import type { CreatedCredential, ManagedAgentProvider, ProviderSkillRef, SessionResourceInput, UploadFileInput } from "../types.js";
6
+ export interface AnthropicProviderRetryOptions {
7
+ maxAttempts?: number | undefined;
8
+ baseDelayMs?: number | undefined;
9
+ maxDelayMs?: number | undefined;
10
+ }
6
11
  export interface AnthropicManagedAgentsProviderOptions {
7
12
  apiKey: string | SecretString;
8
13
  baseUrl?: string;
9
14
  fetch?: typeof fetch;
15
+ retry?: AnthropicProviderRetryOptions | undefined;
10
16
  }
11
17
  export declare class AnthropicManagedAgentsProvider implements ManagedAgentProvider {
12
18
  #private;
@@ -3,14 +3,21 @@ import { redactSecrets, SecretString } from "../../utils/secrets.js";
3
3
  const DEFAULT_BASE_URL = "https://api.anthropic.com";
4
4
  const ANTHROPIC_VERSION = "2023-06-01";
5
5
  const BETA_HEADER = "managed-agents-2026-04-01,files-api-2025-04-14,skills-2025-10-02";
6
+ const DEFAULT_RETRY_OPTIONS = {
7
+ maxAttempts: 3,
8
+ baseDelayMs: 100,
9
+ maxDelayMs: 1_000
10
+ };
6
11
  export class AnthropicManagedAgentsProvider {
7
12
  #apiKey;
8
13
  #baseUrl;
9
14
  #fetch;
15
+ #retry;
10
16
  constructor(options) {
11
17
  this.#apiKey = options.apiKey instanceof SecretString ? options.apiKey : new SecretString(options.apiKey, "anthropicApiKey");
12
18
  this.#baseUrl = options.baseUrl ?? DEFAULT_BASE_URL;
13
19
  this.#fetch = options.fetch ?? fetch;
20
+ this.#retry = normalizeRetryOptions(options.retry);
14
21
  }
15
22
  async createEnvironment(template) {
16
23
  const body = {
@@ -244,22 +251,93 @@ export class AnthropicManagedAgentsProvider {
244
251
  return await response.json();
245
252
  }
246
253
  async #raw(path, init) {
247
- const response = await this.#fetch(`${this.#baseUrl}${path}`, {
248
- ...init,
249
- headers: {
250
- "x-api-key": this.#apiKey.unwrap(),
251
- "anthropic-version": ANTHROPIC_VERSION,
252
- "anthropic-beta": BETA_HEADER,
253
- ...init.headers
254
+ const method = normalizeMethod(init.method);
255
+ const retryable = isRetryableMethod(method);
256
+ let attempt = 0;
257
+ while (true) {
258
+ attempt += 1;
259
+ try {
260
+ const response = await this.#fetch(`${this.#baseUrl}${path}`, {
261
+ ...init,
262
+ method,
263
+ headers: {
264
+ "x-api-key": this.#apiKey.unwrap(),
265
+ "anthropic-version": ANTHROPIC_VERSION,
266
+ "anthropic-beta": BETA_HEADER,
267
+ ...init.headers
268
+ }
269
+ });
270
+ if (response.ok) {
271
+ return response;
272
+ }
273
+ if (retryable && isRetryableStatus(response.status) && attempt < this.#retry.maxAttempts) {
274
+ await discardBody(response);
275
+ await delayBeforeRetry(attempt, this.#retry, init.signal);
276
+ continue;
277
+ }
278
+ const body = await response.text().catch(() => "");
279
+ throw new ProviderError(`Anthropic API request failed: ${response.status} ${redactSecrets(body)}`, { status: response.status });
280
+ }
281
+ catch (error) {
282
+ if (error instanceof ProviderError || isAbortError(error) || !retryable || attempt >= this.#retry.maxAttempts) {
283
+ if (error instanceof ProviderError) {
284
+ throw error;
285
+ }
286
+ throw new ProviderError(`Anthropic API request failed before response: ${redactSecrets(errorMessage(error))}`);
287
+ }
288
+ await delayBeforeRetry(attempt, this.#retry, init.signal);
254
289
  }
255
- });
256
- if (!response.ok) {
257
- const body = await response.text().catch(() => "");
258
- throw new ProviderError(`Anthropic API request failed: ${response.status} ${redactSecrets(body)}`, { status: response.status });
259
290
  }
260
- return response;
261
291
  }
262
292
  }
293
+ function normalizeRetryOptions(options) {
294
+ return {
295
+ maxAttempts: Math.max(1, Math.floor(options?.maxAttempts ?? DEFAULT_RETRY_OPTIONS.maxAttempts)),
296
+ baseDelayMs: Math.max(0, options?.baseDelayMs ?? DEFAULT_RETRY_OPTIONS.baseDelayMs),
297
+ maxDelayMs: Math.max(0, options?.maxDelayMs ?? DEFAULT_RETRY_OPTIONS.maxDelayMs)
298
+ };
299
+ }
300
+ function normalizeMethod(method) {
301
+ return (method ?? "GET").toUpperCase();
302
+ }
303
+ function isRetryableMethod(method) {
304
+ return method === "GET" || method === "HEAD" || method === "DELETE";
305
+ }
306
+ function isRetryableStatus(status) {
307
+ return status === 408 || status === 429 || status >= 500;
308
+ }
309
+ async function discardBody(response) {
310
+ await response.body?.cancel().catch(() => undefined);
311
+ }
312
+ async function delayBeforeRetry(attempt, options, signal) {
313
+ const delayMs = Math.min(options.maxDelayMs, options.baseDelayMs * 2 ** Math.max(0, attempt - 1));
314
+ if (delayMs === 0) {
315
+ throwIfAborted(signal);
316
+ return;
317
+ }
318
+ throwIfAborted(signal);
319
+ await new Promise((resolve, reject) => {
320
+ const timeout = setTimeout(resolve, delayMs);
321
+ signal?.addEventListener("abort", () => {
322
+ clearTimeout(timeout);
323
+ reject(abortError(signal));
324
+ }, { once: true });
325
+ });
326
+ }
327
+ function throwIfAborted(signal) {
328
+ if (signal?.aborted) {
329
+ throw abortError(signal);
330
+ }
331
+ }
332
+ function abortError(signal) {
333
+ return signal.reason instanceof Error ? signal.reason : new Error("Request aborted");
334
+ }
335
+ function isAbortError(error) {
336
+ return error instanceof Error && (error.name === "AbortError" || error.message === "Request aborted");
337
+ }
338
+ function errorMessage(error) {
339
+ return error instanceof Error ? error.message : String(error);
340
+ }
263
341
  function mapNetworking(template) {
264
342
  const network = template.environment.network ?? "restricted";
265
343
  if (network === "unrestricted") {