@andreprado/agentkit 0.1.0-alpha.17 → 0.1.0-alpha.19

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 (64) hide show
  1. package/README.md +3 -0
  2. package/docs/guides/add-channel.md +14 -8
  3. package/docs/guides/add-knowledge.md +10 -0
  4. package/docs/guides/add-managed-composio.md +43 -17
  5. package/docs/guides/channel-security.md +60 -39
  6. package/docs/guides/connect-discord.md +178 -0
  7. package/docs/guides/create-agent.md +13 -0
  8. package/docs/guides/debug-channel.md +147 -0
  9. package/docs/guides/improve-from-production.md +151 -0
  10. package/docs/guides/prepare-deploy.md +30 -14
  11. package/docs/guides/replay-production-traces.md +72 -0
  12. package/docs/guides/run-evals.md +18 -0
  13. package/docs/guides/security-rules.md +5 -5
  14. package/docs/guides/use-provider.md +11 -1
  15. package/docs/llms-full.txt +106 -15
  16. package/docs/llms.txt +22 -4
  17. package/package.json +1 -3
  18. package/src/cli/args.ts +23 -2
  19. package/src/cli/cloud-client.ts +75 -0
  20. package/src/cli/commands/channels.ts +139 -14
  21. package/src/cli/deploy-chat-ui.ts +146 -3
  22. package/src/cli/deploy-readiness.ts +57 -1
  23. package/src/cli/help.ts +32 -8
  24. package/src/cli/index.ts +447 -17
  25. package/src/create-project.ts +13 -2
  26. package/src/index.ts +46 -3
  27. package/src/providers/pi.ts +49 -15
  28. package/src/runtime/channel-test-harness.ts +4 -1
  29. package/src/runtime/channels/discord.ts +887 -0
  30. package/src/runtime/channels.ts +15 -0
  31. package/src/runtime/config.ts +39 -3
  32. package/src/runtime/core/manifest.ts +2 -0
  33. package/src/runtime/dev-server.ts +149 -8
  34. package/src/runtime/evals.ts +27 -6
  35. package/src/runtime/improve.ts +868 -0
  36. package/src/runtime/inspect.ts +1 -0
  37. package/src/runtime/integrations/composio.ts +168 -2
  38. package/src/runtime/knowledge/retrieve.ts +25 -5
  39. package/src/runtime/knowledge/schema.ts +45 -1
  40. package/src/runtime/runtime-contract.ts +54 -0
  41. package/src/runtime/targets/cloudflare/build.ts +479 -194
  42. package/src/runtime/targets/vps/deploy.ts +1 -1
  43. package/src/storage/sqlite.ts +7 -2
  44. package/src/templates/skills/agentkit-capsule/SKILL.md +8 -1
  45. package/src/templates/skills/agentkit-capsule/references/docs-router.md +1 -2
  46. package/src/templates/skills/agentkit-channels/SKILL.md +6 -1
  47. package/src/templates/skills/agentkit-channels/references/channel-debugging.md +2 -1
  48. package/src/templates/skills/agentkit-channels/references/discord.md +93 -0
  49. package/src/templates/skills/agentkit-deploy/SKILL.md +6 -0
  50. package/src/templates/skills/agentkit-evals/SKILL.md +12 -3
  51. package/src/templates/skills/agentkit-improve/SKILL.md +86 -0
  52. package/src/templates/skills/agentkit-improve/references/replay-side-effects.md +18 -0
  53. package/src/templates/skills/agentkit-improve/references/trace-packets.md +22 -0
  54. package/src/templates/skills/agentkit-improve/templates/regression.eval.md +18 -0
  55. package/src/templates/skills/agentkit-integrations/SKILL.md +12 -2
  56. package/src/templates/skills/agentkit-knowledge/SKILL.md +4 -1
  57. package/src/templates/skills/agentkit-provider/SKILL.md +4 -1
  58. package/src/templates/skills/agentkit-security/SKILL.md +3 -2
  59. package/src/templates/skills/agentkit-troubleshooting/SKILL.md +9 -0
  60. package/src/templates/support.ts +4 -2
  61. package/docs/guides/agentkit-skills-architecture.md +0 -472
  62. package/docs/guides/channels-implementation-map.md +0 -243
  63. package/docs/guides/channels-production-handoff.md +0 -118
  64. package/docs/portable-deploy-release-checklist.md +0 -41
package/src/cli/index.ts CHANGED
@@ -21,6 +21,7 @@ import {
21
21
  import { runEvalsFromCwd, writeEvalFromConversation } from "../runtime/evals";
22
22
  import { findAgentKitDocs } from "../runtime/docs";
23
23
  import { listCapsuleEnv, setCapsuleEnv, unsetCapsuleEnv } from "../runtime/env";
24
+ import { collectDeployImproveBundle, collectLocalImproveBundle, generateImproveEvals, replayImproveBundle } from "../runtime/improve";
24
25
  import { checkAgentSpec, initializeAgentSpec } from "../runtime/spec";
25
26
  import { checkDefaultSkillStatus, syncDefaultSkillFiles } from "../runtime/skills";
26
27
  import { initializeSyncScaffold, runCapsuleSync } from "../runtime/sync";
@@ -44,6 +45,12 @@ import {
44
45
  resolveCloudApiUrl,
45
46
  verifyCloudLogin,
46
47
  writeCloudAuth,
48
+ type AccountApiTokenCreateResponse,
49
+ type AccountApiTokenListResponse,
50
+ type BillingCheckoutIntentResponse,
51
+ type BillingCheckoutResponse,
52
+ type BillingClaimResponse,
53
+ type BillingPortalResponse,
47
54
  type CloudMeResponse,
48
55
  type DeployAccessTokenCreateResponse,
49
56
  type DeployAccessTokenListResponse,
@@ -70,6 +77,8 @@ import { handleChannelsCommand } from "./commands/channels";
70
77
  import { handleKnowledgeCommand } from "./commands/knowledge";
71
78
  import { handleTranscribeCommand } from "./commands/transcribe";
72
79
 
80
+ const hostedDeployEntitlement = "agentkit_cloud_deploy";
81
+
73
82
  async function main() {
74
83
  const args = parseArgs(process.argv.slice(2));
75
84
 
@@ -336,10 +345,132 @@ async function main() {
336
345
  return;
337
346
  }
338
347
 
348
+ if (args.command === "improve") {
349
+ const [subcommand, bundlePath] = args.positional;
350
+
351
+ if (subcommand === "collect") {
352
+ const since = parseOptionalStringFlag(args.flags.since, "since", 'agentkit improve collect --since "24h"');
353
+ const conversationId = parseOptionalStringFlag(
354
+ args.flags["conversation-id"] ?? args.flags.conversation,
355
+ "conversation id",
356
+ "agentkit improve collect --conversation-id <id>",
357
+ );
358
+ const out = parseOptionalStringFlag(args.flags.out, "out", "agentkit improve collect --out <directory>");
359
+ const deployState = args.flags.deploy === true ? await requireLocalDeployState() : null;
360
+ const apiUrl = args.flags.deploy === true ? await resolveCloudApiUrl(args.flags.api) : null;
361
+ const cloudAuth = apiUrl ? await readCloudAuthForApiUrl(apiUrl) : null;
362
+ const result = args.flags.deploy === true
363
+ ? await collectDeployImproveBundle(process.cwd(), {
364
+ deployId: deployState?.deploy_id ?? "",
365
+ since,
366
+ conversationId,
367
+ out,
368
+ collector: {
369
+ ...(cloudAuth && apiUrl && deployState
370
+ ? {
371
+ exportEvidence: (input: { deployId: string; since?: string; conversationId?: string }) =>
372
+ fetchDeployImproveEvidence(apiUrl, input),
373
+ }
374
+ : {}),
375
+ listConversations: () => fetchDeployConversationJson(process.cwd(), "/v1/conversations"),
376
+ getTrace: (id: string) =>
377
+ fetchDeployConversationJson(process.cwd(), `/v1/conversations/${encodeURIComponent(id)}/trace`),
378
+ },
379
+ })
380
+ : await collectLocalImproveBundle(process.cwd(), {
381
+ since,
382
+ conversationId,
383
+ out,
384
+ });
385
+
386
+ console.log("Improve bundle collected");
387
+ console.log(`Source: ${result.source}`);
388
+ console.log(`Directory: ${relativePath(result.root, result.directory)}`);
389
+ console.log(`Bundle: ${relativePath(result.root, result.bundlePath)}`);
390
+ console.log(`Report: ${relativePath(result.root, result.reportPath)}`);
391
+ console.log(`Traces: ${result.traceCount}`);
392
+ console.log("");
393
+ console.log(`Next: agentkit improve evals ${relativePath(result.root, result.directory)}`);
394
+ console.log(`Replay: agentkit replay ${relativePath(result.root, result.directory)} --against local`);
395
+ return;
396
+ }
397
+
398
+ if (subcommand === "evals") {
399
+ if (!bundlePath) {
400
+ throw new Error("Missing bundle path. Usage: agentkit improve evals <bundle-dir-or-json> [--force]");
401
+ }
402
+
403
+ const result = await generateImproveEvals(process.cwd(), {
404
+ bundle: bundlePath,
405
+ force: args.flags.force === true,
406
+ });
407
+
408
+ console.log("Improve evals generated");
409
+ console.log(`Bundle: ${relativePath(result.root, result.bundlePath)}`);
410
+ console.log(`Files: ${result.files.length}`);
411
+ for (const file of result.files) {
412
+ console.log(` ${relativePath(result.root, file)}`);
413
+ }
414
+ if (result.skipped.length > 0) {
415
+ console.log(`Skipped: ${result.skipped.length}`);
416
+ for (const skipped of result.skipped) {
417
+ console.log(` ${skipped.trace_id}: ${skipped.reason}`);
418
+ }
419
+ }
420
+ return;
421
+ }
422
+
423
+ throw new Error("Usage: agentkit improve collect [--deploy] [--since <duration|iso>] [--conversation-id <id>] [--out <directory>] | agentkit improve evals <bundle-dir-or-json> [--force]");
424
+ }
425
+
426
+ if (args.command === "replay") {
427
+ const [bundlePath] = args.positional;
428
+
429
+ if (!bundlePath) {
430
+ throw new Error("Missing bundle path. Usage: agentkit replay <bundle-dir-or-json> --against local");
431
+ }
432
+
433
+ const against = parseOptionalStringFlag(args.flags.against, "against", "agentkit replay <bundle> --against local") ?? "local";
434
+
435
+ if (against !== "local") {
436
+ throw new Error("Usage: agentkit replay <bundle-dir-or-json> --against local");
437
+ }
438
+
439
+ const result = await replayImproveBundle(process.cwd(), {
440
+ bundle: bundlePath,
441
+ against,
442
+ });
443
+
444
+ for (const item of result.results) {
445
+ console.log(`${item.status.toUpperCase()} ${item.conversation_id} (${item.turns} turns)`);
446
+ if (item.error) {
447
+ console.log(` - ${item.error}`);
448
+ }
449
+ }
450
+
451
+ console.log("");
452
+ console.log(`Replay passed: ${result.passed}`);
453
+ console.log(`Replay failed: ${result.failed}`);
454
+ console.log(`Replay skipped: ${result.skipped}`);
455
+
456
+ if (result.failed > 0) {
457
+ process.exitCode = 1;
458
+ }
459
+
460
+ return;
461
+ }
462
+
339
463
  if (args.command === "conversations") {
340
464
  const [subcommand, conversationId] = args.positional;
465
+ const fromDeploy = args.flags.deploy === true;
341
466
 
342
467
  if (subcommand === "list") {
468
+ if (fromDeploy) {
469
+ const payload = await fetchDeployConversationJson(process.cwd(), "/v1/conversations");
470
+ printJson(payload);
471
+ return;
472
+ }
473
+
343
474
  const conversations = await listConversationsFromCwd(process.cwd());
344
475
 
345
476
  if (conversations.length === 0) {
@@ -365,7 +496,16 @@ async function main() {
365
496
 
366
497
  if (subcommand === "show") {
367
498
  if (!conversationId) {
368
- throw new Error("Missing conversation id. Usage: agentkit conversations show <conversation-id>");
499
+ throw new Error("Missing conversation id. Usage: agentkit conversations show <conversation-id> [--deploy]");
500
+ }
501
+
502
+ if (fromDeploy) {
503
+ const payload = await fetchDeployConversationJson(
504
+ process.cwd(),
505
+ `/v1/conversations/${encodeURIComponent(conversationId)}`,
506
+ );
507
+ printJson(payload);
508
+ return;
369
509
  }
370
510
 
371
511
  const conversation = await getConversationFromCwd(process.cwd(), conversationId);
@@ -384,7 +524,16 @@ async function main() {
384
524
 
385
525
  if (subcommand === "trace") {
386
526
  if (!conversationId) {
387
- throw new Error("Missing conversation id. Usage: agentkit conversations trace <conversation-id>");
527
+ throw new Error("Missing conversation id. Usage: agentkit conversations trace <conversation-id> [--deploy]");
528
+ }
529
+
530
+ if (fromDeploy) {
531
+ const trace = await fetchDeployConversationJson(
532
+ process.cwd(),
533
+ `/v1/conversations/${encodeURIComponent(conversationId)}/trace`,
534
+ );
535
+ printJson(trace);
536
+ return;
388
537
  }
389
538
 
390
539
  const trace = await getConversationTraceFromCwd(process.cwd(), conversationId);
@@ -392,7 +541,7 @@ async function main() {
392
541
  return;
393
542
  }
394
543
 
395
- throw new Error("Usage: agentkit conversations list | agentkit conversations show <conversation-id> | agentkit conversations trace <conversation-id>");
544
+ throw new Error("Usage: agentkit conversations list [--deploy] | agentkit conversations show <conversation-id> [--deploy] | agentkit conversations trace <conversation-id> [--deploy]");
396
545
  }
397
546
 
398
547
  if (args.command === "knowledge") {
@@ -492,13 +641,15 @@ async function main() {
492
641
  const email = verified.me.account?.email;
493
642
  console.log(email ? `Logged in to AgentKit Cloud as ${email}.` : "AgentKit Cloud token verified and stored.");
494
643
 
495
- const hasCloudflareAlpha = (verified.capabilities.capabilities ?? []).some(
496
- (capability) => capability.name === "cloudflare_deploy_alpha" && capability.status === "active",
644
+ const hasHostedDeploy = (verified.capabilities.capabilities ?? []).some(
645
+ (capability) =>
646
+ (capability.name === "cloudflare_deploy_alpha" || capability.name === hostedDeployEntitlement) &&
647
+ capability.status === "active",
497
648
  );
498
649
  console.log(
499
- hasCloudflareAlpha
500
- ? "Entitlement: cloudflare_deploy_alpha active."
501
- : "Warning: cloudflare_deploy_alpha entitlement was not found for this account.",
650
+ hasHostedDeploy
651
+ ? "Entitlement: hosted deploy active."
652
+ : `Warning: cloudflare_deploy_alpha or ${hostedDeployEntitlement} entitlement was not found for this account.`,
502
653
  );
503
654
 
504
655
  if (process.env.AGENTKIT_CLOUD_API_TOKEN && process.env.AGENTKIT_CLOUD_API_TOKEN !== token) {
@@ -514,6 +665,208 @@ async function main() {
514
665
  return;
515
666
  }
516
667
 
668
+ if (args.command === "account") {
669
+ const [noun, verb, value] = args.positional;
670
+
671
+ if (noun !== "token") {
672
+ throw new Error("Usage: agentkit account token create <name> [--use] [--out <path>] | list | revoke <token-id> [--api <url>]");
673
+ }
674
+
675
+ const apiUrl = await resolveCloudApiUrl(args.flags.api);
676
+
677
+ if (verb === "create" && value) {
678
+ const payload = (await cloudApiRequest(apiUrl, "/v1/account/tokens", {
679
+ method: "POST",
680
+ body: JSON.stringify({ name: value }),
681
+ })) as AccountApiTokenCreateResponse;
682
+ const token = payload.token;
683
+
684
+ if (!token?.token || !token.id) {
685
+ throw new AgentKitError("account_token_invalid", "AgentKit Cloud returned an invalid account token payload.");
686
+ }
687
+
688
+ const outPath = parseOptionalStringFlag(
689
+ args.flags.out,
690
+ "out",
691
+ "agentkit account token create <name> [--api <url>] [--use] [--out <path>]",
692
+ );
693
+
694
+ if (outPath) {
695
+ const absolutePath = resolve(process.cwd(), outPath);
696
+ await writeSecretJson(absolutePath, payload);
697
+ console.log(`Account token written to ${absolutePath}`);
698
+ } else {
699
+ printJson(payload);
700
+ }
701
+
702
+ if (args.flags.use === true) {
703
+ await writeCloudAuth({ apiUrl, token: token.token });
704
+ console.log(`Saved ${token.id} as the current AgentKit Cloud login.`);
705
+ }
706
+
707
+ return;
708
+ }
709
+
710
+ if (verb === "list" && !value) {
711
+ const payload = (await cloudApiRequest(apiUrl, "/v1/account/tokens", {
712
+ method: "GET",
713
+ })) as AccountApiTokenListResponse;
714
+ printJson(payload);
715
+ return;
716
+ }
717
+
718
+ if (verb === "revoke" && value) {
719
+ const payload = await cloudApiRequest(apiUrl, `/v1/account/tokens/${encodeURIComponent(value)}/revoke`, {
720
+ method: "POST",
721
+ });
722
+ printJson(payload);
723
+ return;
724
+ }
725
+
726
+ throw new Error("Usage: agentkit account token create <name> [--use] [--out <path>] | list | revoke <token-id> [--api <url>]");
727
+ }
728
+
729
+ if (args.command === "billing") {
730
+ const [subcommand, intentId] = args.positional;
731
+ const apiUrl = await resolveCloudApiUrl(args.flags.api);
732
+
733
+ if (subcommand === "checkout") {
734
+ const slots = parsePositiveIntegerFlag(
735
+ args.flags.slots,
736
+ "slots",
737
+ "agentkit billing checkout --slots <count> [--email <email>] [--api <url>]",
738
+ );
739
+ const email = parseOptionalStringFlag(
740
+ args.flags.email,
741
+ "email",
742
+ "agentkit billing checkout --slots <count> --email <email>",
743
+ );
744
+ const payload = (await cloudApiRequest(apiUrl, "/v1/billing/checkout", {
745
+ method: "POST",
746
+ body: JSON.stringify({
747
+ slots,
748
+ ...(email ? { email } : {}),
749
+ }),
750
+ })) as BillingCheckoutResponse;
751
+ const checkoutUrl = payload.checkout?.url;
752
+ const billingIntentId = payload.billing_intent?.id;
753
+ const secret = payload.billing_intent?.secret;
754
+
755
+ if (!checkoutUrl || !billingIntentId || !secret) {
756
+ throw new AgentKitError("billing_checkout_invalid", "AgentKit Cloud returned an invalid billing checkout payload.");
757
+ }
758
+
759
+ if (args.flags.json === true) {
760
+ printJson(payload);
761
+ } else {
762
+ console.log("AgentKit Cloud checkout");
763
+ console.log("");
764
+ console.log(`URL: ${checkoutUrl}`);
765
+ console.log(`Intent: ${billingIntentId}`);
766
+ console.log(`Secret: ${secret}`);
767
+ console.log("");
768
+ console.log(`After payment: agentkit billing claim ${billingIntentId} --secret ${secret} --api ${apiUrl}`);
769
+ }
770
+
771
+ if (args.flags.open === true) {
772
+ await openLocalUrl(checkoutUrl);
773
+ }
774
+
775
+ return;
776
+ }
777
+
778
+ if (subcommand === "status" && intentId) {
779
+ const secret = parseRequiredStringFlag(
780
+ args.flags.secret,
781
+ "secret",
782
+ "agentkit billing status <billing-intent-id> --secret <secret> [--api <url>]",
783
+ );
784
+ const payload = (await cloudApiRequest(
785
+ apiUrl,
786
+ `/v1/billing/checkout-intents/${encodeURIComponent(intentId)}?secret=${encodeURIComponent(secret)}`,
787
+ { method: "GET" },
788
+ )) as BillingCheckoutIntentResponse;
789
+ printJson(payload);
790
+ return;
791
+ }
792
+
793
+ if (subcommand === "claim" && intentId) {
794
+ const secret = parseRequiredStringFlag(
795
+ args.flags.secret,
796
+ "secret",
797
+ "agentkit billing claim <billing-intent-id> --secret <secret> [--token-name <name>] [--api <url>]",
798
+ );
799
+ const tokenName = parseOptionalStringFlag(
800
+ args.flags["token-name"],
801
+ "token-name",
802
+ "agentkit billing claim <billing-intent-id> --secret <secret> --token-name <name>",
803
+ );
804
+ const payload = (await cloudApiRequest(apiUrl, `/v1/billing/checkout-intents/${encodeURIComponent(intentId)}/claim`, {
805
+ method: "POST",
806
+ body: JSON.stringify({
807
+ secret,
808
+ ...(tokenName ? { token_name: tokenName } : {}),
809
+ }),
810
+ })) as BillingClaimResponse;
811
+ const token = payload.token;
812
+
813
+ if (!token?.token || !token.id) {
814
+ throw new AgentKitError("billing_claim_invalid", "AgentKit Cloud returned an invalid billing claim payload.");
815
+ }
816
+
817
+ await writeCloudAuth({ apiUrl, token: token.token });
818
+
819
+ const outPath = parseOptionalStringFlag(
820
+ args.flags.out,
821
+ "out",
822
+ "agentkit billing claim <billing-intent-id> --secret <secret> [--out <path>]",
823
+ );
824
+
825
+ if (outPath) {
826
+ const absolutePath = resolve(process.cwd(), outPath);
827
+ await writeSecretJson(absolutePath, payload);
828
+ console.log(`Account token written to ${absolutePath}`);
829
+ } else if (args.flags.json === true) {
830
+ printJson(payload);
831
+ } else {
832
+ console.log("AgentKit Cloud account token claimed and saved.");
833
+ console.log(`Token: ${token.id}`);
834
+ console.log(`API: ${apiUrl}`);
835
+ }
836
+
837
+ return;
838
+ }
839
+
840
+ if (subcommand === "portal") {
841
+ const payload = (await cloudApiRequest(apiUrl, "/v1/billing/portal", {
842
+ method: "POST",
843
+ body: JSON.stringify({}),
844
+ })) as BillingPortalResponse;
845
+ const portalUrl = payload.portal?.url;
846
+
847
+ if (!portalUrl) {
848
+ throw new AgentKitError("billing_portal_invalid", "AgentKit Cloud returned an invalid billing portal payload.");
849
+ }
850
+
851
+ if (args.flags.json === true) {
852
+ printJson(payload);
853
+ } else {
854
+ console.log("AgentKit Cloud billing portal");
855
+ console.log(`URL: ${portalUrl}`);
856
+ }
857
+
858
+ if (args.flags.open === true) {
859
+ await openLocalUrl(portalUrl);
860
+ }
861
+
862
+ return;
863
+ }
864
+
865
+ throw new Error(
866
+ "Usage: agentkit billing checkout --slots <count> [--email <email>] | status <intent-id> --secret <secret> | claim <intent-id> --secret <secret> | portal [--api <url>]",
867
+ );
868
+ }
869
+
517
870
  if (args.command === "deploy") {
518
871
  const [deploySubcommand] = args.positional;
519
872
 
@@ -522,7 +875,7 @@ async function main() {
522
875
  parseOptionalStringFlag(args.flags.message ?? args.flags.smoke, "message", 'agentkit deploy smoke --message "hello"') ??
523
876
  "hello";
524
877
  const state = await requireLocalDeployState();
525
- const token = await readDeployAccessTokenForSmoke(process.cwd(), state);
878
+ const token = await readDeployAccessTokenForHostedRequest(process.cwd());
526
879
  await runDeploySmoke({
527
880
  deployUrl: requireDeployUrl(state),
528
881
  message,
@@ -621,7 +974,7 @@ async function main() {
621
974
  apiUrl,
622
975
  root: result.root,
623
976
  deployId: deploy.deploy.id,
624
- skip: anonymous || !auth?.token || deploy.deploy.access.mode === "public",
977
+ skip: anonymous || !auth?.token,
625
978
  });
626
979
 
627
980
  console.log("");
@@ -634,7 +987,7 @@ async function main() {
634
987
  if (chatAccess?.status === "ready") {
635
988
  console.log(`Chat auth: ${relativePath(process.cwd(), chatAccess.path)}`);
636
989
  } else if (chatAccess?.status === "skipped") {
637
- console.log("Chat auth: public or anonymous deploy; no local chat token was created.");
990
+ console.log("Chat auth: anonymous deploy; no local chat token was created.");
638
991
  } else if (chatAccess?.status === "failed") {
639
992
  console.log(`Chat auth: could not create local chat token. ${formatReadinessError(chatAccess.error)}`);
640
993
  console.log(`Run: agentkit access token create ${defaultDeployChatAccessTokenName} --out ${defaultDeployChatAccessTokenPath}`);
@@ -805,9 +1158,16 @@ async function main() {
805
1158
  const apiUrl = await resolveCloudApiUrl(args.flags.api);
806
1159
 
807
1160
  if (subcommand === "status") {
1161
+ const toolkit = parseOptionalStringFlag(
1162
+ args.flags.toolkit,
1163
+ "toolkit",
1164
+ "agentkit integrations status --toolkit <slug>",
1165
+ );
808
1166
  const payload = await cloudApiRequest(
809
1167
  apiUrl,
810
- `/v1/deploys/${encodeURIComponent(state.deploy_id)}/integrations/composio/status`,
1168
+ `/v1/deploys/${encodeURIComponent(state.deploy_id)}/integrations/composio/status${
1169
+ toolkit ? `?toolkit=${encodeURIComponent(toolkit)}` : ""
1170
+ }`,
811
1171
  { method: "GET" },
812
1172
  );
813
1173
  printJson(payload);
@@ -842,6 +1202,7 @@ async function main() {
842
1202
  redirect_url?: string;
843
1203
  expires_at?: string;
844
1204
  connected_account_id?: string;
1205
+ auth_config_source?: string;
845
1206
  };
846
1207
  };
847
1208
 
@@ -854,6 +1215,9 @@ async function main() {
854
1215
  console.log("Composio connect link");
855
1216
  console.log(`Toolkit: ${link.toolkit ?? toolkit ?? "unknown"}`);
856
1217
  console.log(`User: ${link.user_id ?? "unknown"}`);
1218
+ if (link.auth_config_source) {
1219
+ console.log(`Auth: ${link.auth_config_source}`);
1220
+ }
857
1221
  console.log(`URL: ${link.redirect_url}`);
858
1222
 
859
1223
  if (link.expires_at) {
@@ -1129,11 +1493,7 @@ function requireDeployUrl(state: Pick<LocalDeployState, "deploy_id" | "url">): s
1129
1493
  return state.url;
1130
1494
  }
1131
1495
 
1132
- async function readDeployAccessTokenForSmoke(cwd: string, state: LocalDeployState): Promise<string | undefined> {
1133
- if (state.access?.mode === "public") {
1134
- return undefined;
1135
- }
1136
-
1496
+ async function readDeployAccessTokenForHostedRequest(cwd: string): Promise<string> {
1137
1497
  const root = await findAgentCapsuleRoot(cwd);
1138
1498
  return readDeployAccessTokenForUi(join(root, defaultDeployChatAccessTokenPath));
1139
1499
  }
@@ -1180,6 +1540,62 @@ async function runDeploySmoke(input: { deployUrl: string; message: string; token
1180
1540
  }
1181
1541
  }
1182
1542
 
1543
+ async function fetchDeployConversationJson(cwd: string, path: string): Promise<unknown> {
1544
+ const state = await requireLocalDeployState();
1545
+ const deployUrl = requireDeployUrl(state);
1546
+ const token = await readDeployAccessTokenForHostedRequest(cwd);
1547
+ const headers = new Headers();
1548
+
1549
+ headers.set("Authorization", `Bearer ${token}`);
1550
+
1551
+ let response: Response;
1552
+
1553
+ try {
1554
+ response = await fetch(new URL(path, deployUrl).href, {
1555
+ method: "GET",
1556
+ headers,
1557
+ });
1558
+ } catch (error) {
1559
+ throw new AgentKitError(
1560
+ "deploy_conversation_request_failed",
1561
+ `Could not read hosted conversation data: ${error instanceof Error ? error.message : String(error)}`,
1562
+ );
1563
+ }
1564
+
1565
+ const payload = await response.json().catch(() => null);
1566
+
1567
+ if (!response.ok) {
1568
+ throw new AgentKitError("deploy_conversation_request_failed", readCloudError(payload, response.status));
1569
+ }
1570
+
1571
+ return payload;
1572
+ }
1573
+
1574
+ async function fetchDeployImproveEvidence(
1575
+ apiUrl: string,
1576
+ input: { deployId: string; since?: string; conversationId?: string },
1577
+ ): Promise<unknown | null> {
1578
+ try {
1579
+ return await cloudApiRequest(apiUrl, `/v1/deploys/${encodeURIComponent(input.deployId)}/improve/export`, {
1580
+ method: "POST",
1581
+ body: JSON.stringify({
1582
+ status: "all",
1583
+ ...(input.since ? { since: input.since } : {}),
1584
+ ...(input.conversationId ? { conversation_id: input.conversationId } : {}),
1585
+ }),
1586
+ });
1587
+ } catch (error) {
1588
+ if (
1589
+ isAgentKitError(error) &&
1590
+ (error.code === "improve_evidence_store_not_configured" || error.code === "not_found")
1591
+ ) {
1592
+ return null;
1593
+ }
1594
+
1595
+ throw error;
1596
+ }
1597
+ }
1598
+
1183
1599
  function printJson(value: unknown): void {
1184
1600
  console.log(JSON.stringify(value, null, 2));
1185
1601
  }
@@ -1221,6 +1637,20 @@ async function printJsonOrWrite(value: unknown, outFlag: string | boolean | unde
1221
1637
  console.log(`Deploy access token written to ${absolutePath}`);
1222
1638
  }
1223
1639
 
1640
+ function parsePositiveIntegerFlag(value: string | boolean | undefined, name: string, usage: string): number {
1641
+ if (typeof value !== "string") {
1642
+ throw new Error(`Missing ${name}. Usage: ${usage}`);
1643
+ }
1644
+
1645
+ const parsed = Number(value);
1646
+
1647
+ if (!Number.isInteger(parsed) || parsed <= 0) {
1648
+ throw new Error(`Invalid ${name}. Usage: ${usage}`);
1649
+ }
1650
+
1651
+ return parsed;
1652
+ }
1653
+
1224
1654
  function relativePath(root: string, path: string): string {
1225
1655
  const output = relative(root, path);
1226
1656
  return output.startsWith("..") ? path : output || ".";
@@ -42,8 +42,7 @@ export async function createProject(options: CreateProjectOptions): Promise<Crea
42
42
  }
43
43
 
44
44
  for (const file of files) {
45
- const absolutePath = join(projectPath, file.path);
46
- const directory = absolutePath.slice(0, absolutePath.lastIndexOf("/"));
45
+ const { absolutePath, directory } = resolveProjectFilePath(projectPath, file.path);
47
46
 
48
47
  await mkdir(directory, { recursive: true });
49
48
  await writeFile(absolutePath, file.contents);
@@ -58,6 +57,18 @@ export async function createProject(options: CreateProjectOptions): Promise<Crea
58
57
  };
59
58
  }
60
59
 
60
+ export function resolveProjectFilePath(
61
+ projectPath: string,
62
+ filePath: string,
63
+ pathApi: Pick<typeof import("node:path"), "dirname" | "join"> = { dirname, join },
64
+ ): { absolutePath: string; directory: string } {
65
+ const absolutePath = pathApi.join(projectPath, filePath);
66
+ return {
67
+ absolutePath,
68
+ directory: pathApi.dirname(absolutePath),
69
+ };
70
+ }
71
+
61
72
  function resolveProjectTarget(options: CreateProjectOptions): { name: string; path: string; currentDirectory: boolean } {
62
73
  if (options.name === ".") {
63
74
  const path = resolve(options.cwd);