@andreprado/agentkit 0.1.0-alpha.2 → 0.1.0-alpha.21

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 (142) hide show
  1. package/README.md +68 -6
  2. package/docs/guides/add-channel.md +189 -7
  3. package/docs/guides/add-knowledge.md +144 -0
  4. package/docs/guides/add-managed-composio.md +163 -0
  5. package/docs/guides/add-tool.md +1 -1
  6. package/docs/guides/channel-security.md +128 -32
  7. package/docs/guides/connect-discord.md +178 -0
  8. package/docs/guides/connect-slack.md +126 -0
  9. package/docs/guides/connect-telegram.md +78 -1
  10. package/docs/guides/connect-whatsapp-evolution.md +121 -0
  11. package/docs/guides/connect-whatsapp-uazapi.md +126 -0
  12. package/docs/guides/connect-whatsapp-zapster.md +112 -8
  13. package/docs/guides/create-agent.md +45 -4
  14. package/docs/guides/debug-channel.md +147 -0
  15. package/docs/guides/improve-from-production.md +151 -0
  16. package/docs/guides/prepare-deploy.md +47 -17
  17. package/docs/guides/replay-production-traces.md +72 -0
  18. package/docs/guides/run-evals.md +147 -20
  19. package/docs/guides/security-rules.md +7 -6
  20. package/docs/guides/send-feedback.md +135 -0
  21. package/docs/guides/use-provider.md +27 -3
  22. package/docs/llms-full.txt +348 -55
  23. package/docs/llms.txt +62 -7
  24. package/package.json +2 -5
  25. package/src/cli/args.ts +57 -0
  26. package/src/cli/cloud-client.ts +377 -0
  27. package/src/cli/commands/channels.ts +1586 -0
  28. package/src/cli/commands/feedback.ts +438 -0
  29. package/src/cli/commands/knowledge.ts +136 -0
  30. package/src/cli/commands/transcribe.ts +171 -0
  31. package/src/cli/constants.ts +4 -0
  32. package/src/cli/deploy-chat-ui.ts +535 -0
  33. package/src/cli/deploy-readiness.ts +481 -0
  34. package/src/cli/flags.ts +162 -0
  35. package/src/cli/help.ts +236 -0
  36. package/src/cli/index.ts +1167 -1005
  37. package/src/cli/process.ts +31 -0
  38. package/src/cloud/artifact.ts +139 -0
  39. package/src/cloud/client.ts +80 -0
  40. package/src/cloud/contracts.ts +63 -0
  41. package/src/cloud/index.ts +3 -0
  42. package/src/create-project.ts +21 -6
  43. package/src/index.ts +517 -8
  44. package/src/providers/pi.ts +70 -16
  45. package/src/providers/test.ts +88 -1
  46. package/src/providers/types.ts +7 -0
  47. package/src/runtime/channel-buffer.ts +30 -0
  48. package/src/runtime/channel-test-harness.ts +21 -1
  49. package/src/runtime/channels/discord.ts +896 -0
  50. package/src/runtime/channels/generic-webhook.ts +225 -0
  51. package/src/runtime/channels/slack.ts +646 -0
  52. package/src/runtime/channels/telegram.ts +466 -23
  53. package/src/runtime/channels/whatsapp-evolution.ts +1357 -0
  54. package/src/runtime/channels/whatsapp-meta.ts +9 -0
  55. package/src/runtime/channels/whatsapp-uazapi.ts +1327 -0
  56. package/src/runtime/channels/whatsapp-zapster.ts +677 -40
  57. package/src/runtime/channels.ts +87 -4
  58. package/src/runtime/chat.ts +130 -38
  59. package/src/runtime/config.ts +519 -19
  60. package/src/runtime/core/manifest.ts +103 -5
  61. package/src/runtime/core/targets.ts +5 -5
  62. package/src/runtime/database.ts +93 -2
  63. package/src/runtime/db-commands.ts +9 -0
  64. package/src/runtime/deploy-readiness.ts +46 -4
  65. package/src/runtime/deploy.ts +1 -1
  66. package/src/runtime/dev-server.ts +779 -45
  67. package/src/runtime/env.ts +8 -3
  68. package/src/runtime/evals.ts +589 -43
  69. package/src/runtime/improve.ts +868 -0
  70. package/src/runtime/inspect.ts +194 -4
  71. package/src/runtime/integrations/composio.ts +423 -0
  72. package/src/runtime/knowledge/chunk.ts +333 -0
  73. package/src/runtime/knowledge/config.ts +135 -0
  74. package/src/runtime/knowledge/embeddings.ts +133 -0
  75. package/src/runtime/knowledge/ingest.ts +521 -0
  76. package/src/runtime/knowledge/prompt-policy.ts +30 -0
  77. package/src/runtime/knowledge/retrieve.ts +303 -0
  78. package/src/runtime/knowledge/schema.ts +100 -0
  79. package/src/runtime/knowledge/tool.ts +64 -0
  80. package/src/runtime/knowledge/vector.ts +258 -0
  81. package/src/runtime/prompt-context.ts +141 -0
  82. package/src/runtime/runtime-contract.ts +86 -8
  83. package/src/runtime/skills.ts +95 -0
  84. package/src/runtime/spec.ts +152 -0
  85. package/src/runtime/sync.ts +144 -0
  86. package/src/runtime/targets/cloudflare/build.ts +1468 -203
  87. package/src/runtime/targets/container/server.ts +1 -1
  88. package/src/runtime/targets/vps/deploy.ts +26 -9
  89. package/src/runtime/tool-runner.ts +9 -1
  90. package/src/runtime/tools.ts +128 -2
  91. package/src/runtime/traces.ts +41 -0
  92. package/src/runtime/transcription.ts +483 -0
  93. package/src/storage/sqlite.ts +149 -3
  94. package/src/templates/blank.ts +76 -17
  95. package/src/templates/dentista.ts +1011 -0
  96. package/src/templates/index.ts +2 -0
  97. package/src/templates/skills/agentkit-build-agent/SKILL.md +52 -0
  98. package/src/templates/skills/agentkit-build-agent/templates/appointment-intake.instructions.md +21 -0
  99. package/src/templates/skills/agentkit-build-agent/templates/sales-qualifier.instructions.md +17 -0
  100. package/src/templates/skills/agentkit-build-agent/templates/support-agent.instructions.md +16 -0
  101. package/src/templates/skills/agentkit-capsule/SKILL.md +70 -0
  102. package/src/templates/skills/agentkit-capsule/references/docs-router.md +15 -0
  103. package/src/templates/skills/agentkit-channels/SKILL.md +127 -0
  104. package/src/templates/skills/agentkit-channels/references/channel-buffering.md +65 -0
  105. package/src/templates/skills/agentkit-channels/references/channel-debugging.md +66 -0
  106. package/src/templates/skills/agentkit-channels/references/discord.md +93 -0
  107. package/src/templates/skills/agentkit-channels/references/slack.md +56 -0
  108. package/src/templates/skills/agentkit-channels/references/telegram.md +72 -0
  109. package/src/templates/skills/agentkit-channels/references/whatsapp-evolution.md +57 -0
  110. package/src/templates/skills/agentkit-channels/references/whatsapp-uazapi.md +61 -0
  111. package/src/templates/skills/agentkit-channels/references/whatsapp-zapster.md +77 -0
  112. package/src/templates/skills/agentkit-database/SKILL.md +45 -0
  113. package/src/templates/skills/agentkit-database/templates/appointments.schema.sql +15 -0
  114. package/src/templates/skills/agentkit-database/templates/leads.schema.sql +17 -0
  115. package/src/templates/skills/agentkit-deploy/SKILL.md +50 -0
  116. package/src/templates/skills/agentkit-evals/SKILL.md +109 -0
  117. package/src/templates/skills/agentkit-evals/templates/multi-turn.eval.md +29 -0
  118. package/src/templates/skills/agentkit-evals/templates/no-leak.eval.md +18 -0
  119. package/src/templates/skills/agentkit-evals/templates/smoke.eval.md +18 -0
  120. package/src/templates/skills/agentkit-evals/templates/tool-call.eval.md +27 -0
  121. package/src/templates/skills/agentkit-improve/SKILL.md +86 -0
  122. package/src/templates/skills/agentkit-improve/references/replay-side-effects.md +18 -0
  123. package/src/templates/skills/agentkit-improve/references/trace-packets.md +22 -0
  124. package/src/templates/skills/agentkit-improve/templates/regression.eval.md +18 -0
  125. package/src/templates/skills/agentkit-integrations/SKILL.md +76 -0
  126. package/src/templates/skills/agentkit-knowledge/SKILL.md +43 -0
  127. package/src/templates/skills/agentkit-knowledge/templates/faq.md +14 -0
  128. package/src/templates/skills/agentkit-knowledge/templates/policies.md +14 -0
  129. package/src/templates/skills/agentkit-knowledge/templates/prices.csv +3 -0
  130. package/src/templates/skills/agentkit-prompts/SKILL.md +47 -0
  131. package/src/templates/skills/agentkit-prompts/templates/knowledge-grounded-faq.instructions.md +11 -0
  132. package/src/templates/skills/agentkit-provider/SKILL.md +60 -0
  133. package/src/templates/skills/agentkit-security/SKILL.md +56 -0
  134. package/src/templates/skills/agentkit-tools/SKILL.md +37 -0
  135. package/src/templates/skills/agentkit-tools/examples/database-write.tool.md +35 -0
  136. package/src/templates/skills/agentkit-tools/examples/eval-safe-external-action.tool.md +37 -0
  137. package/src/templates/skills/agentkit-tools/examples/lookup-order.tool.md +46 -0
  138. package/src/templates/skills/agentkit-troubleshooting/SKILL.md +76 -0
  139. package/src/templates/support.ts +77 -18
  140. package/docs/guides/channels-production-handoff.md +0 -99
  141. package/docs/portable-deploy-release-checklist.md +0 -41
  142. package/src/runtime/targets/cloudflare/deploy.ts +0 -5475
package/docs/llms.txt CHANGED
@@ -2,56 +2,110 @@
2
2
 
3
3
  AgentKit creates and runs Agent Capsules: folders with `agentkit.config.ts`, prompts, tools, evals, local storage, and agent-facing docs.
4
4
 
5
- Read `docs/llms-full.txt` when you need the whole operating contract.
5
+ Read `docs/llms-full.txt` only when you need the whole operating contract.
6
6
 
7
7
  Task guides:
8
8
 
9
9
  - Create a capsule: `docs/guides/create-agent.md`
10
10
  - Add a TypeScript tool: `docs/guides/add-tool.md`
11
+ - Add Knowledge from local docs/CSVs: `docs/guides/add-knowledge.md`
11
12
  - Run or prepare evals: `docs/guides/run-evals.md`
13
+ - Improve from production traces: `docs/guides/improve-from-production.md`
14
+ - Replay collected traces locally: `docs/guides/replay-production-traces.md`
15
+ - Send AgentKit product feedback safely: `docs/guides/send-feedback.md`
12
16
  - Switch from `test/fake` to a real provider: `docs/guides/use-provider.md`
13
17
  - Prepare for hosted deploy: `docs/guides/prepare-deploy.md`
14
18
  - Build Cloudflare artifact: `agentkit build --target cloudflare`
15
19
  - Build container artifact: `agentkit build --target container`
16
20
  - Generate VPS handoff: `agentkit deploy --target vps --host agent.example.com --dry-run`
17
21
  - Add hosted channels: `docs/guides/add-channel.md`
22
+ - Add AgentKit-managed Composio: `docs/guides/add-managed-composio.md`
23
+ - Buffer rapid channel messages: `docs/guides/add-channel.md#buffer-bursty-messages`
24
+ - Connect Discord: `docs/guides/connect-discord.md`
25
+ - Connect Slack: `docs/guides/connect-slack.md`
18
26
  - Connect Telegram: `docs/guides/connect-telegram.md`
27
+ - Connect WhatsApp through Evolution API: `docs/guides/connect-whatsapp-evolution.md`
28
+ - Connect WhatsApp through UAZAPI: `docs/guides/connect-whatsapp-uazapi.md`
19
29
  - Connect WhatsApp through Zapster: `docs/guides/connect-whatsapp-zapster.md`
20
30
  - Follow channel webhook and delivery-log safety rules: `docs/guides/channel-security.md`
21
- - Prepare Channels for production: `docs/guides/channels-production-handoff.md`
22
31
  - Follow secret, access, and tool safety rules: `docs/guides/security-rules.md`
23
32
 
24
33
  Current local commands:
25
34
 
26
35
  ```sh
27
- agentkit new <name> --template blank|support
36
+ agentkit new <name> --template blank|support|dentista
37
+ agentkit new <name> --template blank --no-install
28
38
  agentkit docs full
39
+ agentkit env set <NAME> --stdin
29
40
  agentkit env list
30
41
  agentkit env unset <NAME>
31
42
  agentkit handoff codex|claude [goal]
32
43
  agentkit chat --message "hello"
33
44
  agentkit tool <name> --input <path-or-json>
45
+ agentkit knowledge add <path-or-url>
46
+ agentkit knowledge sync
47
+ agentkit knowledge inspect
48
+ agentkit knowledge search <query> [--top-k <number>]
34
49
  agentkit eval run
50
+ agentkit improve collect --deploy --since 24h
51
+ agentkit improve evals .agentkit/improve/<run>
52
+ agentkit replay .agentkit/improve/<run> --against local
53
+ agentkit feedback create --about last-run --kind bug --summary "what failed"
54
+ agentkit feedback send .agentkit/feedback/<draft>.json
35
55
  agentkit conversations list
36
56
  agentkit conversations show <conversation-id>
57
+ agentkit conversations trace <conversation-id> [--deploy]
37
58
  agentkit channels list
38
59
  agentkit channels add telegram support-telegram
60
+ agentkit channels connect whatsapp main-whatsapp --provider evolution
61
+ agentkit channels connect whatsapp support-whatsapp --provider uazapi
62
+ agentkit channels connect discord support-discord
63
+ agentkit channels connect discord server-discord --mode bot
64
+ agentkit channels connect slack support-slack
65
+ agentkit channels connect webhook n8n-webhook
39
66
  agentkit channels setup support-telegram
40
67
  agentkit channels status support-telegram
41
68
  agentkit channels test support-telegram --message "hello"
69
+ agentkit channels test-audio support-telegram --fixture voice-note
70
+ agentkit transcribe smoke --provider groq
42
71
  agentkit channels deliveries list support-telegram
72
+ agentkit integrations status [--toolkit googlecalendar]
73
+ agentkit integrations connect composio --toolkit gmail
74
+ agentkit skills status
75
+ agentkit skills sync
76
+ agentkit billing checkout --slots 1 --email user@example.com
77
+ agentkit billing claim billint_... --secret bsec_...
43
78
  agentkit login --token agk_user_...
79
+ agentkit account token create new-laptop --use
80
+ agentkit account token list
44
81
  agentkit deploy doctor
45
- agentkit deploy
82
+ agentkit deploy --smoke "hello"
46
83
  agentkit deploy status
84
+ agentkit deploy smoke --message "hello"
85
+ agentkit chat-ui --deploy
86
+ agentkit secret set <NAME> --from-local-env
87
+ agentkit secret sync --from-local
47
88
  agentkit secret list
48
- agentkit access token create website-chat
89
+ agentkit access token create website-chat --out .agentkit/website-chat-access-token.json
49
90
  agentkit access token list
50
91
  agentkit inspect
51
92
  agentkit dev
93
+ agentkit open
52
94
  ```
53
95
 
54
- Generated capsules include `AGENTKIT.md` and `AGENTS.md` so Codex, Claude Code, or another coding agent can treat the owner's natural-language request as the brief and start building immediately. `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.
96
+ On Windows PowerShell, if `npm.ps1` or `npx.ps1` is blocked with `PSSecurityException`, run capsule scripts through the `.cmd` shims, for example `npm.cmd run agentkit -- inspect`, `npm.cmd run agentkit -- knowledge sync`, or `npm.cmd run eval`.
97
+
98
+ 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.
99
+
100
+ 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.
101
+
102
+ Hosted Chat UI shows the current conversation id, tool calls, tool errors, and a new-conversation control. Use `agentkit conversations trace <conversation-id> --deploy` to pull the hosted trace from the last deploy.
103
+
104
+ `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.
105
+
106
+ For OpenRouter, prefer model ids or aliases known to the installed Pi SDK, such as `~google/gemini-flash-latest`. If an OpenRouter id is newer than Pi's registry, AgentKit passes the raw id through to OpenRouter with conservative unknown-model metadata; OpenRouter can still reject invalid, inaccessible, or unsupported models.
107
+
108
+ AgentKit injects the current ISO timestamp, local date, weekday, local date/time, and timezone dynamically into every chat run. Set `timeZone` in `agentkit.config.ts` for scheduling agents so "today", "tomorrow", and weekdays resolve in the business/user timezone; otherwise AgentKit falls back to `AGENTKIT_TIME_ZONE`, valid `TZ`, then the runtime default. Do not hardcode today's date in prompts.
55
109
 
56
110
  Current local endpoints from `agentkit dev`:
57
111
 
@@ -60,6 +114,7 @@ GET /_agentkit
60
114
  POST /v1/chat
61
115
  GET /v1/conversations
62
116
  GET /v1/conversations/:id
117
+ GET /v1/conversations/:id/trace
63
118
  ```
64
119
 
65
- 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.
120
+ Local `.env` is for development only. Use `.env.schema` as the committed secret-name contract; local AgentKit commands load `.env` directly. Hosted deploys require an AgentKit Cloud account with `cloudflare_deploy_alpha` or purchased/manual deploy slots. Use `agentkit billing checkout` + `agentkit billing claim` for first-time paid access, or `agentkit login --token ...` when the user already has an `agk_user_...` token. Production uses managed secrets in the hosted contract.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@andreprado/agentkit",
3
- "version": "0.1.0-alpha.2",
3
+ "version": "0.1.0-alpha.21",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "repository": {
@@ -18,9 +18,6 @@
18
18
  "!src/**/*.test.ts",
19
19
  "!src/runtime/fixtures",
20
20
  "docs",
21
- "!docs/guides/backend-contracts.md",
22
- "!docs/guides/debug-channel.md",
23
- "!docs/guides/deploy-agentkit-cloud-hostinger.md",
24
21
  "README.md"
25
22
  ],
26
23
  "publishConfig": {
@@ -35,8 +32,8 @@
35
32
  "dependencies": {
36
33
  "@earendil-works/pi-ai": "^0.75.5",
37
34
  "@earendil-works/pi-coding-agent": "^0.75.5",
35
+ "@libsql/client": "^0.15.15",
38
36
  "esbuild": "^0.28.0",
39
- "postgres": "^3.4.9",
40
37
  "tsx": "^4.22.3",
41
38
  "typebox": "^1.1.38"
42
39
  },
@@ -0,0 +1,57 @@
1
+ export type ParsedArgs = {
2
+ command?: string;
3
+ positional: string[];
4
+ flags: Record<string, string | boolean>;
5
+ };
6
+
7
+ const dashPrefixedValueFlags = new Set([
8
+ "brief",
9
+ "input",
10
+ "input-json",
11
+ "message",
12
+ "prompt",
13
+ "smoke",
14
+ ]);
15
+
16
+ export function parseArgs(argv: string[]): ParsedArgs {
17
+ const [command, ...rest] = argv;
18
+ const positional: string[] = [];
19
+ const flags: Record<string, string | boolean> = {};
20
+
21
+ for (let index = 0; index < rest.length; index += 1) {
22
+ const value = rest[index];
23
+
24
+ if (value === "--") {
25
+ positional.push(...rest.slice(index + 1));
26
+ break;
27
+ }
28
+
29
+ if (!value.startsWith("--")) {
30
+ positional.push(value);
31
+ continue;
32
+ }
33
+
34
+ const equalsIndex = value.indexOf("=");
35
+ const name = equalsIndex === -1 ? value.slice(2) : value.slice(2, equalsIndex);
36
+
37
+ if (equalsIndex !== -1) {
38
+ flags[name] = value.slice(equalsIndex + 1);
39
+ continue;
40
+ }
41
+
42
+ const next = rest[index + 1];
43
+
44
+ if (next && (dashPrefixedValueFlags.has(name) || !next.startsWith("--"))) {
45
+ flags[name] = next;
46
+ index += 1;
47
+ } else {
48
+ flags[name] = true;
49
+ }
50
+ }
51
+
52
+ return { command, positional, flags };
53
+ }
54
+
55
+ export function isHelpRequested(args: ParsedArgs): boolean {
56
+ return args.flags.help === true || args.flags.h === true || args.positional.includes("--help") || args.positional.includes("-h");
57
+ }
@@ -0,0 +1,377 @@
1
+ import { chmod, 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 CloudManagedComposioResponse = {
43
+ managed_composio?: {
44
+ entitlement?: "active" | "missing" | string;
45
+ api_key?: "set" | "missing" | string;
46
+ toolkits?: Array<{
47
+ toolkit?: string;
48
+ auth_config_env?: string;
49
+ auth_config?: "set" | "missing" | string;
50
+ auth_config_source?: "project" | "account" | "global" | "env" | string;
51
+ }>;
52
+ };
53
+ };
54
+
55
+ export type CloudProjectResolveResponse = {
56
+ project?: {
57
+ id?: string;
58
+ name?: string;
59
+ owner_state?: "anonymous" | "claimed";
60
+ };
61
+ };
62
+
63
+ export type DeployAccessTokenCreateResponse = {
64
+ access_token?: {
65
+ id?: string;
66
+ deploy_id?: string;
67
+ account_id?: string;
68
+ name?: string;
69
+ token?: string;
70
+ created_at?: string;
71
+ expires_at?: string;
72
+ last_used_at?: string;
73
+ };
74
+ };
75
+
76
+ export type DeployAccessTokenListResponse = {
77
+ access_tokens?: Array<{
78
+ id?: string;
79
+ deploy_id?: string;
80
+ account_id?: string;
81
+ name?: string;
82
+ created_at?: string;
83
+ expires_at?: string;
84
+ last_used_at?: string;
85
+ }>;
86
+ };
87
+
88
+ export type AccountApiTokenCreateResponse = {
89
+ token?: {
90
+ id?: string;
91
+ account_id?: string;
92
+ name?: string;
93
+ token?: string;
94
+ created_at?: string;
95
+ expires_at?: string;
96
+ last_used_at?: string;
97
+ };
98
+ };
99
+
100
+ export type AccountApiTokenListResponse = {
101
+ tokens?: Array<{
102
+ id?: string;
103
+ account_id?: string;
104
+ name?: string;
105
+ created_at?: string;
106
+ expires_at?: string;
107
+ last_used_at?: string;
108
+ revoked_at?: string;
109
+ }>;
110
+ };
111
+
112
+ export type BillingCheckoutResponse = {
113
+ checkout?: {
114
+ id?: string;
115
+ url?: string;
116
+ };
117
+ billing_intent?: {
118
+ id?: string;
119
+ account_id?: string;
120
+ email?: string;
121
+ requested_slots?: number;
122
+ status?: string;
123
+ secret?: string;
124
+ };
125
+ };
126
+
127
+ export type BillingCheckoutIntentResponse = {
128
+ billing_intent?: {
129
+ id?: string;
130
+ account_id?: string;
131
+ email?: string;
132
+ requested_slots?: number;
133
+ status?: string;
134
+ checkout_session_id?: string;
135
+ stripe_customer_id?: string;
136
+ stripe_subscription_id?: string;
137
+ completed_at?: string;
138
+ token_claimed_at?: string;
139
+ };
140
+ };
141
+
142
+ export type BillingClaimResponse = BillingCheckoutIntentResponse & AccountApiTokenCreateResponse;
143
+
144
+ export type BillingPortalResponse = {
145
+ portal?: {
146
+ url?: string;
147
+ };
148
+ };
149
+
150
+ export type CloudSecretsResponse = {
151
+ secrets?: Array<{
152
+ name?: string;
153
+ status?: string;
154
+ updated_at?: string;
155
+ }>;
156
+ };
157
+
158
+ export type FeedbackSendResponse = {
159
+ feedback?: {
160
+ id?: string;
161
+ account_id?: string;
162
+ kind?: string;
163
+ summary?: string;
164
+ status?: string;
165
+ client_report_id?: string;
166
+ created_at?: string;
167
+ };
168
+ };
169
+
170
+ export function cloudAuthPath(): string {
171
+ return join(homedir(), ".agentkit", "cloud.json");
172
+ }
173
+
174
+ export async function readCloudAuth(): Promise<CloudAuthConfig | null> {
175
+ if (process.env.AGENTKIT_CLOUD_API_TOKEN) {
176
+ return {
177
+ apiUrl: process.env.AGENTKIT_CLOUD_API_URL ?? defaultAgentKitCloudApiUrl,
178
+ token: process.env.AGENTKIT_CLOUD_API_TOKEN,
179
+ source: "environment",
180
+ };
181
+ }
182
+
183
+ try {
184
+ const parsed = JSON.parse(await readFile(cloudAuthPath(), "utf8"));
185
+
186
+ if (parsed && typeof parsed === "object" && typeof parsed.token === "string") {
187
+ return {
188
+ apiUrl: typeof parsed.apiUrl === "string" ? parsed.apiUrl : defaultAgentKitCloudApiUrl,
189
+ token: parsed.token,
190
+ source: "file",
191
+ };
192
+ }
193
+ } catch {
194
+ return null;
195
+ }
196
+
197
+ return null;
198
+ }
199
+
200
+ export async function readCloudAuthForApiUrl(apiUrl: string): Promise<CloudAuthConfig | null> {
201
+ const auth = await readCloudAuth();
202
+
203
+ if (auth?.source === "file" && !cloudAuthMatchesApiUrl(auth, apiUrl)) {
204
+ return null;
205
+ }
206
+
207
+ return auth;
208
+ }
209
+
210
+ export async function writeCloudAuth(config: CloudAuthConfig): Promise<void> {
211
+ await mkdir(join(homedir(), ".agentkit"), { recursive: true });
212
+ await writeFile(cloudAuthPath(), `${JSON.stringify(config, null, 2)}\n`, { mode: 0o600 });
213
+ await chmod(cloudAuthPath(), 0o600);
214
+ }
215
+
216
+ export async function clearCloudAuth(): Promise<void> {
217
+ await rm(cloudAuthPath(), { force: true });
218
+ }
219
+
220
+ export async function resolveCloudApiUrl(flag: string | boolean | undefined): Promise<string> {
221
+ if (flag !== undefined) {
222
+ return parseCloudApiUrl(flag);
223
+ }
224
+
225
+ const auth = await readCloudAuth();
226
+ return auth?.apiUrl ?? parseCloudApiUrl(undefined);
227
+ }
228
+
229
+ export async function verifyCloudLogin(
230
+ apiUrl: string,
231
+ token: string,
232
+ ): Promise<{ me: CloudMeResponse; capabilities: CloudCapabilitiesResponse }> {
233
+ const me = await cloudApiRequestWithToken<CloudMeResponse>(apiUrl, "/v1/me", token, { method: "GET" });
234
+ const capabilities = await cloudApiRequestWithToken<CloudCapabilitiesResponse>(
235
+ apiUrl,
236
+ "/v1/me/capabilities",
237
+ token,
238
+ { method: "GET" },
239
+ );
240
+
241
+ return { me, capabilities };
242
+ }
243
+
244
+ export async function cloudGet<T>(apiUrl: string, path: string): Promise<T> {
245
+ const response = await cloudFetch(apiUrl, path);
246
+ const payload = await response.json();
247
+
248
+ if (!response.ok) {
249
+ throw new Error(readCloudError(payload, response.status));
250
+ }
251
+
252
+ return payload as T;
253
+ }
254
+
255
+ export async function cloudPost<T>(apiUrl: string, path: string, body: unknown): Promise<T> {
256
+ const response = await cloudFetch(apiUrl, path, {
257
+ method: "POST",
258
+ headers: { "Content-Type": "application/json" },
259
+ body: JSON.stringify(body),
260
+ });
261
+ const payload = await response.json();
262
+
263
+ if (!response.ok) {
264
+ throw new Error(readCloudError(payload, response.status));
265
+ }
266
+
267
+ return payload as T;
268
+ }
269
+
270
+ export async function cloudFetch(apiUrl: string, path: string, init: RequestInit = {}): Promise<Response> {
271
+ const headers = new Headers(init.headers);
272
+ const auth = await readCloudAuthForApiUrl(apiUrl);
273
+ const apiToken = auth?.token;
274
+
275
+ if (apiToken && !headers.has("Authorization")) {
276
+ headers.set("Authorization", `Bearer ${apiToken}`);
277
+ }
278
+
279
+ return fetch(new URL(path, parseCloudApiUrl(apiUrl)).href, {
280
+ ...init,
281
+ headers,
282
+ });
283
+ }
284
+
285
+ function cloudAuthMatchesApiUrl(auth: CloudAuthConfig, apiUrl: string): boolean {
286
+ return parseCloudApiUrl(auth.apiUrl) === parseCloudApiUrl(apiUrl);
287
+ }
288
+
289
+ export async function cloudApiRequest(apiUrl: string, path: string, init: RequestInit): Promise<unknown> {
290
+ const auth = await readCloudAuthForApiUrl(apiUrl);
291
+ const headers = new Headers(init.headers);
292
+ const apiToken = auth?.token;
293
+
294
+ if (!headers.has("Content-Type") && init.body !== undefined) {
295
+ headers.set("Content-Type", "application/json");
296
+ }
297
+
298
+ if (apiToken && !headers.has("Authorization")) {
299
+ headers.set("Authorization", `Bearer ${apiToken}`);
300
+ }
301
+
302
+ const response = await fetch(new URL(path, parseCloudApiUrl(apiUrl)).href, {
303
+ ...init,
304
+ headers,
305
+ });
306
+ const payload = await response.json().catch(() => null);
307
+
308
+ if (!response.ok) {
309
+ const code =
310
+ payload && typeof payload === "object" && "error" in payload
311
+ ? String((payload as { error?: { code?: unknown } }).error?.code ?? "cloud_request_failed")
312
+ : "cloud_request_failed";
313
+ let message = readCloudError(payload, response.status);
314
+
315
+ if (code === "auth_token_invalid") {
316
+ message = `${message} Token source: ${auth ? formatCloudAuthSource(auth) : "none"}. Run: agentkit login --token <token>`;
317
+ }
318
+
319
+ throw new AgentKitError(code, message);
320
+ }
321
+
322
+ return payload;
323
+ }
324
+
325
+ export async function cloudApiRequestWithToken<T>(
326
+ apiUrl: string,
327
+ path: string,
328
+ token: string,
329
+ init: RequestInit,
330
+ ): Promise<T> {
331
+ const headers = new Headers(init.headers);
332
+
333
+ if (!headers.has("Content-Type") && init.body !== undefined) {
334
+ headers.set("Content-Type", "application/json");
335
+ }
336
+
337
+ headers.set("Authorization", `Bearer ${token}`);
338
+
339
+ const response = await fetch(new URL(path, parseCloudApiUrl(apiUrl)).href, {
340
+ ...init,
341
+ headers,
342
+ });
343
+ const payload = await response.json().catch(() => null);
344
+
345
+ if (!response.ok) {
346
+ const code =
347
+ payload && typeof payload === "object" && "error" in payload
348
+ ? String((payload as { error?: { code?: unknown } }).error?.code ?? "cloud_request_failed")
349
+ : "cloud_request_failed";
350
+ throw new AgentKitError(code, readCloudError(payload, response.status));
351
+ }
352
+
353
+ return payload as T;
354
+ }
355
+
356
+ export function readCloudError(payload: unknown, status: number): string {
357
+ if (payload && typeof payload === "object" && "error" in payload) {
358
+ const error = (payload as { error?: { message?: unknown } }).error;
359
+ if (typeof error?.message === "string") {
360
+ return error.message;
361
+ }
362
+ }
363
+
364
+ return `AgentKit Cloud request failed with HTTP ${status}.`;
365
+ }
366
+
367
+ export function formatCloudAuthSource(auth: CloudAuthConfig): string {
368
+ if (auth.source === "environment") {
369
+ return "AGENTKIT_CLOUD_API_TOKEN";
370
+ }
371
+
372
+ if (auth.source === "file") {
373
+ return cloudAuthPath();
374
+ }
375
+
376
+ return "AgentKit Cloud auth";
377
+ }