@andreprado/agentkit 0.1.0-alpha.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. package/README.md +69 -0
  2. package/bin/agentkit.mjs +23 -0
  3. package/docs/guides/add-channel.md +114 -0
  4. package/docs/guides/add-knowledge.md +134 -0
  5. package/docs/guides/add-tool.md +342 -0
  6. package/docs/guides/agentkit-skills-architecture.md +471 -0
  7. package/docs/guides/channel-security.md +81 -0
  8. package/docs/guides/channels-implementation-map.md +243 -0
  9. package/docs/guides/channels-production-handoff.md +102 -0
  10. package/docs/guides/connect-telegram.md +110 -0
  11. package/docs/guides/connect-whatsapp-zapster.md +119 -0
  12. package/docs/guides/create-agent.md +220 -0
  13. package/docs/guides/prepare-deploy.md +209 -0
  14. package/docs/guides/run-evals.md +179 -0
  15. package/docs/guides/security-rules.md +156 -0
  16. package/docs/guides/use-provider.md +140 -0
  17. package/docs/llms-full.txt +876 -0
  18. package/docs/llms.txt +83 -0
  19. package/docs/portable-deploy-release-checklist.md +41 -0
  20. package/package.json +47 -0
  21. package/src/cli/args.ts +36 -0
  22. package/src/cli/cloud-client.ts +265 -0
  23. package/src/cli/commands/channels.ts +810 -0
  24. package/src/cli/commands/knowledge.ts +136 -0
  25. package/src/cli/constants.ts +4 -0
  26. package/src/cli/deploy-chat-ui.ts +392 -0
  27. package/src/cli/deploy-readiness.ts +348 -0
  28. package/src/cli/flags.ts +162 -0
  29. package/src/cli/help.ts +184 -0
  30. package/src/cli/index.ts +1276 -0
  31. package/src/cli/process.ts +31 -0
  32. package/src/cloud/artifact.ts +139 -0
  33. package/src/cloud/client.ts +79 -0
  34. package/src/cloud/contracts.ts +63 -0
  35. package/src/cloud/index.ts +3 -0
  36. package/src/create-project.ts +177 -0
  37. package/src/index.ts +408 -0
  38. package/src/providers/index.ts +25 -0
  39. package/src/providers/pi.ts +286 -0
  40. package/src/providers/test.ts +133 -0
  41. package/src/providers/types.ts +34 -0
  42. package/src/runtime/build.ts +43 -0
  43. package/src/runtime/channel-buffer.ts +30 -0
  44. package/src/runtime/channel-test-harness.ts +112 -0
  45. package/src/runtime/channels/telegram.ts +360 -0
  46. package/src/runtime/channels/website.ts +132 -0
  47. package/src/runtime/channels/whatsapp-meta.ts +71 -0
  48. package/src/runtime/channels/whatsapp-zapster.ts +278 -0
  49. package/src/runtime/channels.ts +138 -0
  50. package/src/runtime/chat.ts +218 -0
  51. package/src/runtime/config.ts +684 -0
  52. package/src/runtime/conversations.ts +38 -0
  53. package/src/runtime/core/deploy-state.ts +54 -0
  54. package/src/runtime/core/manifest.ts +213 -0
  55. package/src/runtime/core/targets.ts +133 -0
  56. package/src/runtime/database.ts +256 -0
  57. package/src/runtime/db-commands.ts +167 -0
  58. package/src/runtime/deploy-readiness.ts +105 -0
  59. package/src/runtime/deploy.ts +1 -0
  60. package/src/runtime/dev-server.ts +1247 -0
  61. package/src/runtime/docs.ts +36 -0
  62. package/src/runtime/env.ts +152 -0
  63. package/src/runtime/errors.ts +13 -0
  64. package/src/runtime/evals.ts +509 -0
  65. package/src/runtime/inspect.ts +203 -0
  66. package/src/runtime/knowledge/chunk.ts +333 -0
  67. package/src/runtime/knowledge/config.ts +135 -0
  68. package/src/runtime/knowledge/embeddings.ts +133 -0
  69. package/src/runtime/knowledge/ingest.ts +521 -0
  70. package/src/runtime/knowledge/prompt-policy.ts +30 -0
  71. package/src/runtime/knowledge/retrieve.ts +283 -0
  72. package/src/runtime/knowledge/schema.ts +56 -0
  73. package/src/runtime/knowledge/tool.ts +64 -0
  74. package/src/runtime/knowledge/vector.ts +258 -0
  75. package/src/runtime/runtime-contract.ts +93 -0
  76. package/src/runtime/spec.ts +152 -0
  77. package/src/runtime/sync.ts +144 -0
  78. package/src/runtime/targets/cloudflare/build.ts +2517 -0
  79. package/src/runtime/targets/container/build.ts +146 -0
  80. package/src/runtime/targets/container/server.ts +33 -0
  81. package/src/runtime/targets/vps/deploy.ts +206 -0
  82. package/src/runtime/tool-runner.ts +65 -0
  83. package/src/runtime/tools.ts +470 -0
  84. package/src/runtime/traces.ts +41 -0
  85. package/src/storage/sqlite.ts +1118 -0
  86. package/src/templates/blank.ts +394 -0
  87. package/src/templates/dentista.ts +1003 -0
  88. package/src/templates/index.ts +33 -0
  89. package/src/templates/skills/agentkit-build-agent/SKILL.md +51 -0
  90. package/src/templates/skills/agentkit-build-agent/templates/appointment-intake.instructions.md +20 -0
  91. package/src/templates/skills/agentkit-build-agent/templates/sales-qualifier.instructions.md +17 -0
  92. package/src/templates/skills/agentkit-build-agent/templates/support-agent.instructions.md +16 -0
  93. package/src/templates/skills/agentkit-capsule/SKILL.md +62 -0
  94. package/src/templates/skills/agentkit-capsule/references/docs-router.md +15 -0
  95. package/src/templates/skills/agentkit-channels/SKILL.md +62 -0
  96. package/src/templates/skills/agentkit-channels/references/channel-buffering.md +58 -0
  97. package/src/templates/skills/agentkit-channels/references/channel-debugging.md +41 -0
  98. package/src/templates/skills/agentkit-channels/references/telegram.md +38 -0
  99. package/src/templates/skills/agentkit-channels/references/whatsapp-zapster.md +44 -0
  100. package/src/templates/skills/agentkit-database/SKILL.md +45 -0
  101. package/src/templates/skills/agentkit-database/templates/appointments.schema.sql +15 -0
  102. package/src/templates/skills/agentkit-database/templates/leads.schema.sql +17 -0
  103. package/src/templates/skills/agentkit-deploy/SKILL.md +44 -0
  104. package/src/templates/skills/agentkit-evals/SKILL.md +60 -0
  105. package/src/templates/skills/agentkit-evals/templates/multi-turn.eval.md +22 -0
  106. package/src/templates/skills/agentkit-evals/templates/no-leak.eval.md +14 -0
  107. package/src/templates/skills/agentkit-evals/templates/smoke.eval.md +14 -0
  108. package/src/templates/skills/agentkit-evals/templates/tool-call.eval.md +18 -0
  109. package/src/templates/skills/agentkit-knowledge/SKILL.md +40 -0
  110. package/src/templates/skills/agentkit-knowledge/templates/faq.md +14 -0
  111. package/src/templates/skills/agentkit-knowledge/templates/policies.md +14 -0
  112. package/src/templates/skills/agentkit-knowledge/templates/prices.csv +3 -0
  113. package/src/templates/skills/agentkit-prompts/SKILL.md +45 -0
  114. package/src/templates/skills/agentkit-prompts/templates/knowledge-grounded-faq.instructions.md +11 -0
  115. package/src/templates/skills/agentkit-provider/SKILL.md +57 -0
  116. package/src/templates/skills/agentkit-security/SKILL.md +55 -0
  117. package/src/templates/skills/agentkit-tools/SKILL.md +36 -0
  118. package/src/templates/skills/agentkit-tools/examples/database-write.tool.md +35 -0
  119. package/src/templates/skills/agentkit-tools/examples/eval-safe-external-action.tool.md +37 -0
  120. package/src/templates/skills/agentkit-tools/examples/lookup-order.tool.md +46 -0
  121. package/src/templates/skills/agentkit-troubleshooting/SKILL.md +52 -0
  122. package/src/templates/support.ts +401 -0
package/docs/llms.txt ADDED
@@ -0,0 +1,83 @@
1
+ # AgentKit LLM Index
2
+
3
+ AgentKit creates and runs Agent Capsules: folders with `agentkit.config.ts`, prompts, tools, evals, local storage, and agent-facing docs.
4
+
5
+ Read `docs/llms-full.txt` only when you need the whole operating contract.
6
+
7
+ Task guides:
8
+
9
+ - Create a capsule: `docs/guides/create-agent.md`
10
+ - Add a TypeScript tool: `docs/guides/add-tool.md`
11
+ - Add Knowledge from local docs/CSVs: `docs/guides/add-knowledge.md`
12
+ - Run or prepare evals: `docs/guides/run-evals.md`
13
+ - Switch from `test/fake` to a real provider: `docs/guides/use-provider.md`
14
+ - Prepare for hosted deploy: `docs/guides/prepare-deploy.md`
15
+ - Build Cloudflare artifact: `agentkit build --target cloudflare`
16
+ - Build container artifact: `agentkit build --target container`
17
+ - Generate VPS handoff: `agentkit deploy --target vps --host agent.example.com --dry-run`
18
+ - Add hosted channels: `docs/guides/add-channel.md`
19
+ - Buffer rapid channel messages: `docs/guides/add-channel.md#buffer-bursty-messages`
20
+ - Connect Telegram: `docs/guides/connect-telegram.md`
21
+ - Connect WhatsApp through Zapster: `docs/guides/connect-whatsapp-zapster.md`
22
+ - Follow channel webhook and delivery-log safety rules: `docs/guides/channel-security.md`
23
+ - Prepare Channels for production: `docs/guides/channels-production-handoff.md`
24
+ - Follow secret, access, and tool safety rules: `docs/guides/security-rules.md`
25
+ - Plan repo-local skills for coding agents: `docs/guides/agentkit-skills-architecture.md`
26
+
27
+ Current local commands:
28
+
29
+ ```sh
30
+ agentkit new <name> --template blank|support|dentista
31
+ agentkit new <name> --template blank --no-install
32
+ agentkit docs full
33
+ agentkit env set <NAME> --stdin
34
+ agentkit env list
35
+ agentkit env unset <NAME>
36
+ agentkit handoff codex|claude [goal]
37
+ agentkit chat --message "hello"
38
+ agentkit tool <name> --input <path-or-json>
39
+ agentkit knowledge add <path-or-url>
40
+ agentkit knowledge sync
41
+ agentkit knowledge inspect
42
+ agentkit knowledge search <query> [--top-k <number>]
43
+ agentkit eval run
44
+ agentkit conversations list
45
+ agentkit conversations show <conversation-id>
46
+ agentkit channels list
47
+ agentkit channels add telegram support-telegram
48
+ agentkit channels setup support-telegram
49
+ agentkit channels status support-telegram
50
+ agentkit channels test support-telegram --message "hello"
51
+ agentkit channels deliveries list support-telegram
52
+ agentkit login --token agk_user_...
53
+ agentkit deploy doctor
54
+ agentkit deploy --smoke "hello"
55
+ agentkit deploy status
56
+ agentkit deploy smoke --message "hello"
57
+ agentkit chat-ui --deploy
58
+ agentkit secret set <NAME> --from-local-env
59
+ agentkit secret sync --from-local
60
+ agentkit secret list
61
+ agentkit access token create website-chat --out .agentkit/website-chat-access-token.json
62
+ agentkit access token list
63
+ agentkit inspect
64
+ agentkit dev
65
+ agentkit open
66
+ ```
67
+
68
+ Generated capsules include `AGENTKIT.md`, `AGENTS.md`, and a repo-local `skills/` pack so Codex, Claude Code, or another coding agent can treat the owner's natural-language request as the brief and start building immediately without loading the full contract by default. Start with `skills/agentkit-capsule/SKILL.md`, then load the task skill for the current work. `agentkit handoff codex "Develop an ophthalmology office intake agent"` is an optional prompt-printing shortcut for users who are not already inside a coding-agent workspace. There is no wizard or recipe layer: the coding agent edits the capsule directly from the scaffold and contract.
69
+
70
+ UI testing is part of the handoff. For local UI testing, run `agentkit dev`, open the printed `Chat:` URL, and tell the owner the exact URL. After hosted deploy, run `agentkit chat-ui --deploy`, open the printed `Chat:` URL, and tell the owner it is connected to the deploy.
71
+
72
+ `test/fake` is deterministic and validates scaffold, direct tool calls, and fake-provider evals. It does not validate natural conversation quality. Before claiming real conversation behavior has been tested, ask the owner which provider to use: OpenRouter, OpenAI, Anthropic, or another supported provider. Do not choose for them.
73
+
74
+ Current local endpoints from `agentkit dev`:
75
+
76
+ ```txt
77
+ GET /_agentkit
78
+ POST /v1/chat
79
+ GET /v1/conversations
80
+ GET /v1/conversations/:id
81
+ ```
82
+
83
+ Local `.env` is for development only. Use `.env.schema` as the committed secret-name contract; local AgentKit commands load `.env` directly. Hosted alpha deploys require `cloudflare_deploy_alpha` through `agentkit login --token ...`; production uses managed secrets in the hosted contract.
@@ -0,0 +1,41 @@
1
+ # Portable Deploy Release Checklist
2
+
3
+ Run this before merging portable deploy target work.
4
+
5
+ ## Tests
6
+
7
+ ```sh
8
+ bun test
9
+ npm run typecheck
10
+ npm run agentkit -- build --target cloudflare
11
+ npm run agentkit -- build --target container
12
+ npm run agentkit -- deploy --target vps --host agent.example.com --dry-run
13
+ docker compose -f .agentkit/build/vps/compose.yaml config
14
+ ```
15
+
16
+ ## Smoke
17
+
18
+ - Cloudflare build contains `worker.js`, `wrangler.jsonc`, `durable-object-schema.sql`, and `agent.manifest.json`.
19
+ - Container build contains `server.js`, `Dockerfile`, `migrations/`, and `agent.manifest.json`.
20
+ - VPS build contains `compose.yaml`, `.env.production.example`, `SECRETS.md`, and `PRODUCTION_HANDOFF.md`.
21
+ - `/health`, `/_agentkit`, `/chat`, `/tools/:name`, `/files/:key`, and channel webhook fixtures pass on the local/container runtime.
22
+
23
+ ## Secrets
24
+
25
+ ```sh
26
+ rg -n "sk-|OPENAI_API_KEY=.*[A-Za-z0-9]" .agentkit/build || true
27
+ ```
28
+
29
+ Expected: no secret values. Generated files may contain secret names only.
30
+
31
+ ## Production Handoff
32
+
33
+ - Cloudflare deploy has target-aware `.agentkit/deploy.json` with `target`, `runtime`, and `resources`.
34
+ - VPS handoff documents `PORT`, `AGENTKIT_SQLITE_PATH`, reverse proxy expectations, smoke checks, SQLite backup, Postgres upgrade path, and rollback.
35
+ - Rollback command is present in `.agentkit/build/vps/PRODUCTION_HANDOFF.md`.
36
+
37
+ ## External Smokes
38
+
39
+ - Cloudflare deployed smoke requires Cloudflare credentials and a provider key.
40
+ - Docker image smoke requires a running Docker daemon.
41
+ - Telegram/Zapster real send smoke requires explicit provider credentials.
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "@andreprado/agentkit",
3
+ "version": "0.1.0-alpha.10",
4
+ "private": false,
5
+ "type": "module",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/andrehfp/agentkit.git",
9
+ "directory": "packages/agentkit"
10
+ },
11
+ "exports": {
12
+ ".": "./src/index.ts",
13
+ "./runtime/container": "./src/runtime/targets/container/server.ts"
14
+ },
15
+ "files": [
16
+ "bin",
17
+ "src",
18
+ "!src/**/*.test.ts",
19
+ "!src/runtime/fixtures",
20
+ "docs",
21
+ "!docs/guides/backend-contracts.md",
22
+ "!docs/guides/debug-channel.md",
23
+ "!docs/guides/deploy-agentkit-cloud-hostinger.md",
24
+ "README.md"
25
+ ],
26
+ "publishConfig": {
27
+ "access": "public"
28
+ },
29
+ "engines": {
30
+ "node": ">=24"
31
+ },
32
+ "bin": {
33
+ "agentkit": "bin/agentkit.mjs"
34
+ },
35
+ "dependencies": {
36
+ "@earendil-works/pi-ai": "^0.75.5",
37
+ "@earendil-works/pi-coding-agent": "^0.75.5",
38
+ "@libsql/client": "^0.15.15",
39
+ "esbuild": "^0.28.0",
40
+ "tsx": "^4.22.3",
41
+ "typebox": "^1.1.38"
42
+ },
43
+ "devDependencies": {
44
+ "@types/node": "^24.12.4",
45
+ "bun-types": "^1.3.0"
46
+ }
47
+ }
@@ -0,0 +1,36 @@
1
+ export type ParsedArgs = {
2
+ command?: string;
3
+ positional: string[];
4
+ flags: Record<string, string | boolean>;
5
+ };
6
+
7
+ export function parseArgs(argv: string[]): ParsedArgs {
8
+ const [command, ...rest] = argv;
9
+ const positional: string[] = [];
10
+ const flags: Record<string, string | boolean> = {};
11
+
12
+ for (let index = 0; index < rest.length; index += 1) {
13
+ const value = rest[index];
14
+
15
+ if (!value.startsWith("--")) {
16
+ positional.push(value);
17
+ continue;
18
+ }
19
+
20
+ const name = value.slice(2);
21
+ const next = rest[index + 1];
22
+
23
+ if (next && !next.startsWith("--")) {
24
+ flags[name] = next;
25
+ index += 1;
26
+ } else {
27
+ flags[name] = true;
28
+ }
29
+ }
30
+
31
+ return { command, positional, flags };
32
+ }
33
+
34
+ export function isHelpRequested(args: ParsedArgs): boolean {
35
+ return args.flags.help === true || args.flags.h === true || args.positional.includes("--help") || args.positional.includes("-h");
36
+ }
@@ -0,0 +1,265 @@
1
+ import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
2
+ import { homedir } from "node:os";
3
+ import { join } from "node:path";
4
+
5
+ import { AgentKitError } from "../runtime/errors";
6
+ import { defaultAgentKitCloudApiUrl } from "./constants";
7
+ import { parseCloudApiUrl } from "./flags";
8
+
9
+ export type CloudAuthConfig = {
10
+ apiUrl: string;
11
+ token: string;
12
+ source?: "environment" | "file";
13
+ };
14
+
15
+ export type CloudMeResponse = {
16
+ account?: {
17
+ email?: string;
18
+ status?: string;
19
+ };
20
+ };
21
+
22
+ export type CloudCapabilitiesResponse = {
23
+ capabilities?: Array<{
24
+ name?: string;
25
+ status?: string;
26
+ }>;
27
+ };
28
+
29
+ export type CloudLimitsResponse = {
30
+ online_agents?: {
31
+ account?: {
32
+ used?: number | null;
33
+ limit?: number | null;
34
+ };
35
+ global?: {
36
+ used?: number | null;
37
+ limit?: number | null;
38
+ };
39
+ };
40
+ };
41
+
42
+ export type DeployAccessTokenCreateResponse = {
43
+ access_token?: {
44
+ id?: string;
45
+ deploy_id?: string;
46
+ name?: string;
47
+ token?: string;
48
+ };
49
+ };
50
+
51
+ export type DeployAccessTokenListResponse = {
52
+ access_tokens?: Array<{
53
+ id?: string;
54
+ deploy_id?: string;
55
+ name?: string;
56
+ }>;
57
+ };
58
+
59
+ export type CloudSecretsResponse = {
60
+ secrets?: Array<{
61
+ name?: string;
62
+ status?: string;
63
+ updated_at?: string;
64
+ }>;
65
+ };
66
+
67
+ export function cloudAuthPath(): string {
68
+ return join(homedir(), ".agentkit", "cloud.json");
69
+ }
70
+
71
+ export async function readCloudAuth(): Promise<CloudAuthConfig | null> {
72
+ if (process.env.AGENTKIT_CLOUD_API_TOKEN) {
73
+ return {
74
+ apiUrl: process.env.AGENTKIT_CLOUD_API_URL ?? defaultAgentKitCloudApiUrl,
75
+ token: process.env.AGENTKIT_CLOUD_API_TOKEN,
76
+ source: "environment",
77
+ };
78
+ }
79
+
80
+ try {
81
+ const parsed = JSON.parse(await readFile(cloudAuthPath(), "utf8"));
82
+
83
+ if (parsed && typeof parsed === "object" && typeof parsed.token === "string") {
84
+ return {
85
+ apiUrl: typeof parsed.apiUrl === "string" ? parsed.apiUrl : defaultAgentKitCloudApiUrl,
86
+ token: parsed.token,
87
+ source: "file",
88
+ };
89
+ }
90
+ } catch {
91
+ return null;
92
+ }
93
+
94
+ return null;
95
+ }
96
+
97
+ export async function writeCloudAuth(config: CloudAuthConfig): Promise<void> {
98
+ await mkdir(join(homedir(), ".agentkit"), { recursive: true });
99
+ await writeFile(cloudAuthPath(), `${JSON.stringify(config, null, 2)}\n`, { mode: 0o600 });
100
+ }
101
+
102
+ export async function clearCloudAuth(): Promise<void> {
103
+ await rm(cloudAuthPath(), { force: true });
104
+ }
105
+
106
+ export async function resolveCloudApiUrl(flag: string | boolean | undefined): Promise<string> {
107
+ if (flag !== undefined) {
108
+ return parseCloudApiUrl(flag);
109
+ }
110
+
111
+ const auth = await readCloudAuth();
112
+ return auth?.apiUrl ?? parseCloudApiUrl(undefined);
113
+ }
114
+
115
+ export async function verifyCloudLogin(
116
+ apiUrl: string,
117
+ token: string,
118
+ ): Promise<{ me: CloudMeResponse; capabilities: CloudCapabilitiesResponse }> {
119
+ const me = await cloudApiRequestWithToken<CloudMeResponse>(apiUrl, "/v1/me", token, { method: "GET" });
120
+ const capabilities = await cloudApiRequestWithToken<CloudCapabilitiesResponse>(
121
+ apiUrl,
122
+ "/v1/me/capabilities",
123
+ token,
124
+ { method: "GET" },
125
+ );
126
+
127
+ return { me, capabilities };
128
+ }
129
+
130
+ export async function cloudGet<T>(apiUrl: string, path: string): Promise<T> {
131
+ const response = await cloudFetch(apiUrl, path);
132
+ const payload = await response.json();
133
+
134
+ if (!response.ok) {
135
+ throw new Error(readCloudError(payload, response.status));
136
+ }
137
+
138
+ return payload as T;
139
+ }
140
+
141
+ export async function cloudPost<T>(apiUrl: string, path: string, body: unknown): Promise<T> {
142
+ const response = await cloudFetch(apiUrl, path, {
143
+ method: "POST",
144
+ headers: { "Content-Type": "application/json" },
145
+ body: JSON.stringify(body),
146
+ });
147
+ const payload = await response.json();
148
+
149
+ if (!response.ok) {
150
+ throw new Error(readCloudError(payload, response.status));
151
+ }
152
+
153
+ return payload as T;
154
+ }
155
+
156
+ export async function cloudFetch(apiUrl: string, path: string, init: RequestInit = {}): Promise<Response> {
157
+ const headers = new Headers(init.headers);
158
+ const auth = await readCloudAuth();
159
+ const apiToken =
160
+ auth?.source === "file" && !cloudAuthMatchesApiUrl(auth, apiUrl)
161
+ ? undefined
162
+ : auth?.token;
163
+
164
+ if (apiToken && !headers.has("Authorization")) {
165
+ headers.set("Authorization", `Bearer ${apiToken}`);
166
+ }
167
+
168
+ return fetch(new URL(path, parseCloudApiUrl(apiUrl)).href, {
169
+ ...init,
170
+ headers,
171
+ });
172
+ }
173
+
174
+ function cloudAuthMatchesApiUrl(auth: CloudAuthConfig, apiUrl: string): boolean {
175
+ return parseCloudApiUrl(auth.apiUrl) === parseCloudApiUrl(apiUrl);
176
+ }
177
+
178
+ export async function cloudApiRequest(apiUrl: string, path: string, init: RequestInit): Promise<unknown> {
179
+ const auth = await readCloudAuth();
180
+ const headers = new Headers(init.headers);
181
+
182
+ if (!headers.has("Content-Type") && init.body !== undefined) {
183
+ headers.set("Content-Type", "application/json");
184
+ }
185
+
186
+ if (auth?.token && !headers.has("Authorization")) {
187
+ headers.set("Authorization", `Bearer ${auth.token}`);
188
+ }
189
+
190
+ const response = await fetch(new URL(path, parseCloudApiUrl(apiUrl)).href, {
191
+ ...init,
192
+ headers,
193
+ });
194
+ const payload = await response.json().catch(() => null);
195
+
196
+ if (!response.ok) {
197
+ const code =
198
+ payload && typeof payload === "object" && "error" in payload
199
+ ? String((payload as { error?: { code?: unknown } }).error?.code ?? "cloud_request_failed")
200
+ : "cloud_request_failed";
201
+ let message = readCloudError(payload, response.status);
202
+
203
+ if (code === "auth_token_invalid") {
204
+ message = `${message} Token source: ${auth ? formatCloudAuthSource(auth) : "none"}. Run: agentkit login --token <token>`;
205
+ }
206
+
207
+ throw new AgentKitError(code, message);
208
+ }
209
+
210
+ return payload;
211
+ }
212
+
213
+ export async function cloudApiRequestWithToken<T>(
214
+ apiUrl: string,
215
+ path: string,
216
+ token: string,
217
+ init: RequestInit,
218
+ ): Promise<T> {
219
+ const headers = new Headers(init.headers);
220
+
221
+ if (!headers.has("Content-Type") && init.body !== undefined) {
222
+ headers.set("Content-Type", "application/json");
223
+ }
224
+
225
+ headers.set("Authorization", `Bearer ${token}`);
226
+
227
+ const response = await fetch(new URL(path, parseCloudApiUrl(apiUrl)).href, {
228
+ ...init,
229
+ headers,
230
+ });
231
+ const payload = await response.json().catch(() => null);
232
+
233
+ if (!response.ok) {
234
+ const code =
235
+ payload && typeof payload === "object" && "error" in payload
236
+ ? String((payload as { error?: { code?: unknown } }).error?.code ?? "cloud_request_failed")
237
+ : "cloud_request_failed";
238
+ throw new AgentKitError(code, readCloudError(payload, response.status));
239
+ }
240
+
241
+ return payload as T;
242
+ }
243
+
244
+ export function readCloudError(payload: unknown, status: number): string {
245
+ if (payload && typeof payload === "object" && "error" in payload) {
246
+ const error = (payload as { error?: { message?: unknown } }).error;
247
+ if (typeof error?.message === "string") {
248
+ return error.message;
249
+ }
250
+ }
251
+
252
+ return `AgentKit Cloud request failed with HTTP ${status}.`;
253
+ }
254
+
255
+ export function formatCloudAuthSource(auth: CloudAuthConfig): string {
256
+ if (auth.source === "environment") {
257
+ return "AGENTKIT_CLOUD_API_TOKEN";
258
+ }
259
+
260
+ if (auth.source === "file") {
261
+ return cloudAuthPath();
262
+ }
263
+
264
+ return "AgentKit Cloud auth";
265
+ }