@andreprado/agentkit 0.1.0-alpha.18 → 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.
- package/README.md +3 -0
- package/docs/guides/add-channel.md +12 -6
- package/docs/guides/add-knowledge.md +10 -0
- package/docs/guides/add-managed-composio.md +4 -2
- package/docs/guides/channel-security.md +26 -2
- package/docs/guides/connect-discord.md +178 -0
- package/docs/guides/create-agent.md +13 -0
- package/docs/guides/debug-channel.md +8 -2
- package/docs/guides/improve-from-production.md +151 -0
- package/docs/guides/prepare-deploy.md +29 -8
- package/docs/guides/replay-production-traces.md +72 -0
- package/docs/guides/run-evals.md +18 -0
- package/docs/guides/security-rules.md +5 -5
- package/docs/guides/use-provider.md +11 -1
- package/docs/llms-full.txt +100 -11
- package/docs/llms.txt +17 -1
- package/package.json +1 -1
- package/src/cli/args.ts +23 -2
- package/src/cli/cloud-client.ts +63 -0
- package/src/cli/commands/channels.ts +139 -14
- package/src/cli/deploy-readiness.ts +5 -2
- package/src/cli/help.ts +26 -2
- package/src/cli/index.ts +382 -17
- package/src/create-project.ts +13 -2
- package/src/index.ts +42 -3
- package/src/providers/pi.ts +49 -15
- package/src/runtime/channel-test-harness.ts +4 -1
- package/src/runtime/channels/discord.ts +887 -0
- package/src/runtime/channels.ts +15 -0
- package/src/runtime/config.ts +35 -3
- package/src/runtime/dev-server.ts +149 -8
- package/src/runtime/evals.ts +27 -6
- package/src/runtime/improve.ts +868 -0
- package/src/runtime/knowledge/retrieve.ts +25 -5
- package/src/runtime/knowledge/schema.ts +45 -1
- package/src/runtime/runtime-contract.ts +54 -0
- package/src/runtime/targets/cloudflare/build.ts +248 -193
- package/src/runtime/targets/vps/deploy.ts +1 -1
- package/src/storage/sqlite.ts +7 -2
- package/src/templates/skills/agentkit-capsule/SKILL.md +8 -1
- package/src/templates/skills/agentkit-capsule/references/docs-router.md +1 -2
- package/src/templates/skills/agentkit-channels/SKILL.md +6 -1
- package/src/templates/skills/agentkit-channels/references/channel-debugging.md +2 -1
- package/src/templates/skills/agentkit-channels/references/discord.md +93 -0
- package/src/templates/skills/agentkit-deploy/SKILL.md +6 -0
- package/src/templates/skills/agentkit-evals/SKILL.md +12 -3
- package/src/templates/skills/agentkit-improve/SKILL.md +86 -0
- package/src/templates/skills/agentkit-improve/references/replay-side-effects.md +18 -0
- package/src/templates/skills/agentkit-improve/references/trace-packets.md +22 -0
- package/src/templates/skills/agentkit-improve/templates/regression.eval.md +18 -0
- package/src/templates/skills/agentkit-integrations/SKILL.md +1 -0
- package/src/templates/skills/agentkit-knowledge/SKILL.md +4 -1
- package/src/templates/skills/agentkit-provider/SKILL.md +4 -1
- package/src/templates/skills/agentkit-security/SKILL.md +3 -2
- package/src/templates/skills/agentkit-troubleshooting/SKILL.md +9 -0
- package/src/templates/support.ts +4 -2
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,6 +345,121 @@ 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;
|
|
341
465
|
const fromDeploy = args.flags.deploy === true;
|
|
@@ -517,13 +641,15 @@ async function main() {
|
|
|
517
641
|
const email = verified.me.account?.email;
|
|
518
642
|
console.log(email ? `Logged in to AgentKit Cloud as ${email}.` : "AgentKit Cloud token verified and stored.");
|
|
519
643
|
|
|
520
|
-
const
|
|
521
|
-
(capability) =>
|
|
644
|
+
const hasHostedDeploy = (verified.capabilities.capabilities ?? []).some(
|
|
645
|
+
(capability) =>
|
|
646
|
+
(capability.name === "cloudflare_deploy_alpha" || capability.name === hostedDeployEntitlement) &&
|
|
647
|
+
capability.status === "active",
|
|
522
648
|
);
|
|
523
649
|
console.log(
|
|
524
|
-
|
|
525
|
-
? "Entitlement:
|
|
526
|
-
:
|
|
650
|
+
hasHostedDeploy
|
|
651
|
+
? "Entitlement: hosted deploy active."
|
|
652
|
+
: `Warning: cloudflare_deploy_alpha or ${hostedDeployEntitlement} entitlement was not found for this account.`,
|
|
527
653
|
);
|
|
528
654
|
|
|
529
655
|
if (process.env.AGENTKIT_CLOUD_API_TOKEN && process.env.AGENTKIT_CLOUD_API_TOKEN !== token) {
|
|
@@ -539,6 +665,208 @@ async function main() {
|
|
|
539
665
|
return;
|
|
540
666
|
}
|
|
541
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
|
+
|
|
542
870
|
if (args.command === "deploy") {
|
|
543
871
|
const [deploySubcommand] = args.positional;
|
|
544
872
|
|
|
@@ -547,7 +875,7 @@ async function main() {
|
|
|
547
875
|
parseOptionalStringFlag(args.flags.message ?? args.flags.smoke, "message", 'agentkit deploy smoke --message "hello"') ??
|
|
548
876
|
"hello";
|
|
549
877
|
const state = await requireLocalDeployState();
|
|
550
|
-
const token = await
|
|
878
|
+
const token = await readDeployAccessTokenForHostedRequest(process.cwd());
|
|
551
879
|
await runDeploySmoke({
|
|
552
880
|
deployUrl: requireDeployUrl(state),
|
|
553
881
|
message,
|
|
@@ -646,7 +974,7 @@ async function main() {
|
|
|
646
974
|
apiUrl,
|
|
647
975
|
root: result.root,
|
|
648
976
|
deployId: deploy.deploy.id,
|
|
649
|
-
skip: anonymous || !auth?.token
|
|
977
|
+
skip: anonymous || !auth?.token,
|
|
650
978
|
});
|
|
651
979
|
|
|
652
980
|
console.log("");
|
|
@@ -659,7 +987,7 @@ async function main() {
|
|
|
659
987
|
if (chatAccess?.status === "ready") {
|
|
660
988
|
console.log(`Chat auth: ${relativePath(process.cwd(), chatAccess.path)}`);
|
|
661
989
|
} else if (chatAccess?.status === "skipped") {
|
|
662
|
-
console.log("Chat auth:
|
|
990
|
+
console.log("Chat auth: anonymous deploy; no local chat token was created.");
|
|
663
991
|
} else if (chatAccess?.status === "failed") {
|
|
664
992
|
console.log(`Chat auth: could not create local chat token. ${formatReadinessError(chatAccess.error)}`);
|
|
665
993
|
console.log(`Run: agentkit access token create ${defaultDeployChatAccessTokenName} --out ${defaultDeployChatAccessTokenPath}`);
|
|
@@ -874,6 +1202,7 @@ async function main() {
|
|
|
874
1202
|
redirect_url?: string;
|
|
875
1203
|
expires_at?: string;
|
|
876
1204
|
connected_account_id?: string;
|
|
1205
|
+
auth_config_source?: string;
|
|
877
1206
|
};
|
|
878
1207
|
};
|
|
879
1208
|
|
|
@@ -886,6 +1215,9 @@ async function main() {
|
|
|
886
1215
|
console.log("Composio connect link");
|
|
887
1216
|
console.log(`Toolkit: ${link.toolkit ?? toolkit ?? "unknown"}`);
|
|
888
1217
|
console.log(`User: ${link.user_id ?? "unknown"}`);
|
|
1218
|
+
if (link.auth_config_source) {
|
|
1219
|
+
console.log(`Auth: ${link.auth_config_source}`);
|
|
1220
|
+
}
|
|
889
1221
|
console.log(`URL: ${link.redirect_url}`);
|
|
890
1222
|
|
|
891
1223
|
if (link.expires_at) {
|
|
@@ -1161,11 +1493,7 @@ function requireDeployUrl(state: Pick<LocalDeployState, "deploy_id" | "url">): s
|
|
|
1161
1493
|
return state.url;
|
|
1162
1494
|
}
|
|
1163
1495
|
|
|
1164
|
-
async function
|
|
1165
|
-
if (state.access?.mode === "public") {
|
|
1166
|
-
return undefined;
|
|
1167
|
-
}
|
|
1168
|
-
|
|
1496
|
+
async function readDeployAccessTokenForHostedRequest(cwd: string): Promise<string> {
|
|
1169
1497
|
const root = await findAgentCapsuleRoot(cwd);
|
|
1170
1498
|
return readDeployAccessTokenForUi(join(root, defaultDeployChatAccessTokenPath));
|
|
1171
1499
|
}
|
|
@@ -1215,12 +1543,10 @@ async function runDeploySmoke(input: { deployUrl: string; message: string; token
|
|
|
1215
1543
|
async function fetchDeployConversationJson(cwd: string, path: string): Promise<unknown> {
|
|
1216
1544
|
const state = await requireLocalDeployState();
|
|
1217
1545
|
const deployUrl = requireDeployUrl(state);
|
|
1218
|
-
const token = await
|
|
1546
|
+
const token = await readDeployAccessTokenForHostedRequest(cwd);
|
|
1219
1547
|
const headers = new Headers();
|
|
1220
1548
|
|
|
1221
|
-
|
|
1222
|
-
headers.set("Authorization", `Bearer ${token}`);
|
|
1223
|
-
}
|
|
1549
|
+
headers.set("Authorization", `Bearer ${token}`);
|
|
1224
1550
|
|
|
1225
1551
|
let response: Response;
|
|
1226
1552
|
|
|
@@ -1245,6 +1571,31 @@ async function fetchDeployConversationJson(cwd: string, path: string): Promise<u
|
|
|
1245
1571
|
return payload;
|
|
1246
1572
|
}
|
|
1247
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
|
+
|
|
1248
1599
|
function printJson(value: unknown): void {
|
|
1249
1600
|
console.log(JSON.stringify(value, null, 2));
|
|
1250
1601
|
}
|
|
@@ -1286,6 +1637,20 @@ async function printJsonOrWrite(value: unknown, outFlag: string | boolean | unde
|
|
|
1286
1637
|
console.log(`Deploy access token written to ${absolutePath}`);
|
|
1287
1638
|
}
|
|
1288
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
|
+
|
|
1289
1654
|
function relativePath(root: string, path: string): string {
|
|
1290
1655
|
const output = relative(root, path);
|
|
1291
1656
|
return output.startsWith("..") ? path : output || ".";
|
package/src/create-project.ts
CHANGED
|
@@ -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 =
|
|
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);
|
package/src/index.ts
CHANGED
|
@@ -2,9 +2,10 @@ export type AgentRuntime = "local" | "edge";
|
|
|
2
2
|
export type AgentProviderName = "test" | "openai" | "anthropic" | "openrouter" | "custom";
|
|
3
3
|
export type AccessMode = "private" | "token" | "public";
|
|
4
4
|
export type ToolVisibility = "user" | "internal";
|
|
5
|
-
export type ChannelType = "website" | "telegram" | "whatsapp";
|
|
6
|
-
export type ChannelProvider = "agentkit" | "telegram" | "zapster" | "meta";
|
|
5
|
+
export type ChannelType = "website" | "telegram" | "whatsapp" | "discord";
|
|
6
|
+
export type ChannelProvider = "agentkit" | "telegram" | "zapster" | "meta" | "discord";
|
|
7
7
|
export type WhatsappChannelProvider = "zapster" | "meta";
|
|
8
|
+
export type DiscordChannelMode = "interactions" | "bot";
|
|
8
9
|
export type TelegramAllowedUpdate = "message";
|
|
9
10
|
export type ChannelAudioMode = "off" | "reject" | "transcribe";
|
|
10
11
|
export type TranscriptionProviderName = "test" | "openai" | "groq";
|
|
@@ -143,7 +144,26 @@ export type WhatsappChannelConfig = {
|
|
|
143
144
|
audio?: ChannelAudioConfig;
|
|
144
145
|
};
|
|
145
146
|
|
|
146
|
-
export type
|
|
147
|
+
export type DiscordChannelInput = {
|
|
148
|
+
name: string;
|
|
149
|
+
mode?: DiscordChannelMode;
|
|
150
|
+
secrets?: string[];
|
|
151
|
+
limits?: ChannelLimits;
|
|
152
|
+
buffer?: ChannelBufferInput;
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
export type DiscordChannelConfig = {
|
|
156
|
+
type: "discord";
|
|
157
|
+
provider: "discord";
|
|
158
|
+
name: string;
|
|
159
|
+
mode: DiscordChannelMode;
|
|
160
|
+
secrets: string[];
|
|
161
|
+
limits?: ChannelLimits;
|
|
162
|
+
buffer?: ChannelBufferConfig;
|
|
163
|
+
audio?: never;
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
export type AgentChannel = WebsiteChannelConfig | TelegramChannelConfig | WhatsappChannelConfig | DiscordChannelConfig;
|
|
147
167
|
|
|
148
168
|
export type IntegrationTagsConfig = {
|
|
149
169
|
enable?: string[];
|
|
@@ -428,6 +448,24 @@ export function whatsappChannel(input: WhatsappChannelInput): WhatsappChannelCon
|
|
|
428
448
|
};
|
|
429
449
|
}
|
|
430
450
|
|
|
451
|
+
export function discordChannel(input: DiscordChannelInput): DiscordChannelConfig {
|
|
452
|
+
const mode = input.mode ?? "interactions";
|
|
453
|
+
|
|
454
|
+
return {
|
|
455
|
+
type: "discord",
|
|
456
|
+
provider: "discord",
|
|
457
|
+
name: input.name,
|
|
458
|
+
mode,
|
|
459
|
+
secrets: normalizeChannelSecrets(input.secrets ?? defaultDiscordChannelSecrets(mode), "discord channel"),
|
|
460
|
+
...(input.limits ? { limits: input.limits } : {}),
|
|
461
|
+
...(input.buffer ? { buffer: normalizeChannelBuffer(input.buffer, "discord channel") } : {}),
|
|
462
|
+
};
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
function defaultDiscordChannelSecrets(mode: DiscordChannelMode): string[] {
|
|
466
|
+
return mode === "bot" ? ["DISCORD_BOT_TOKEN"] : ["DISCORD_PUBLIC_KEY"];
|
|
467
|
+
}
|
|
468
|
+
|
|
431
469
|
function defaultWhatsappChannelSecrets(provider: WhatsappChannelProvider): string[] {
|
|
432
470
|
if (provider === "zapster") {
|
|
433
471
|
return ["ZAPSTER_API_KEY", "ZAPSTER_INSTANCE_ID", "ZAPSTER_WEBHOOK_ID"];
|
|
@@ -649,6 +687,7 @@ export type {
|
|
|
649
687
|
ChannelMediaDownloadResult,
|
|
650
688
|
ChannelMessageContentType,
|
|
651
689
|
ChannelMessageRole,
|
|
690
|
+
ChannelReplyTarget,
|
|
652
691
|
ChannelSendInput,
|
|
653
692
|
ChannelSendResult,
|
|
654
693
|
ChannelStatusInput,
|
package/src/providers/pi.ts
CHANGED
|
@@ -19,6 +19,9 @@ import type { ProviderAdapter, ProviderRunInput, ProviderRunResult } from "./typ
|
|
|
19
19
|
|
|
20
20
|
const PI_PROVIDER_NAMES = ["openai", "anthropic", "openrouter"] as const satisfies AgentProviderName[];
|
|
21
21
|
const MAX_TOOL_TURNS = 8;
|
|
22
|
+
const OPENROUTER_BASE_URL = "https://openrouter.ai/api/v1";
|
|
23
|
+
const UNKNOWN_OPENROUTER_CONTEXT_WINDOW = 128000;
|
|
24
|
+
const UNKNOWN_OPENROUTER_MAX_TOKENS = 8192;
|
|
22
25
|
|
|
23
26
|
export const piProviderAdapters: ProviderAdapter[] = PI_PROVIDER_NAMES.map((name) => ({
|
|
24
27
|
name,
|
|
@@ -189,25 +192,56 @@ function formatSecretList(names: string[]): string {
|
|
|
189
192
|
return `one of: ${names.join(", ")}`;
|
|
190
193
|
}
|
|
191
194
|
|
|
192
|
-
function resolveModel(provider: Provider, modelId: string): Model<any> {
|
|
193
|
-
const
|
|
195
|
+
export function resolveModel(provider: Provider, modelId: string): Model<any> {
|
|
196
|
+
const model = getModel(provider as any, modelId as any) as Model<any> | undefined;
|
|
194
197
|
|
|
195
|
-
if (
|
|
196
|
-
|
|
197
|
-
"provider_model_unsupported",
|
|
198
|
-
`Pi SDK could not resolve provider "${provider}" model "${modelId}".`,
|
|
199
|
-
);
|
|
198
|
+
if (model) {
|
|
199
|
+
return model;
|
|
200
200
|
}
|
|
201
201
|
|
|
202
|
-
|
|
203
|
-
return
|
|
204
|
-
} catch (error) {
|
|
205
|
-
throw new AgentKitError(
|
|
206
|
-
"provider_model_unsupported",
|
|
207
|
-
`Pi SDK could not resolve provider "${provider}" model "${modelId}".`,
|
|
208
|
-
{ cause: error },
|
|
209
|
-
);
|
|
202
|
+
if (provider === "openrouter") {
|
|
203
|
+
return createOpenRouterPassThroughModel(modelId);
|
|
210
204
|
}
|
|
205
|
+
|
|
206
|
+
throw new AgentKitError(
|
|
207
|
+
"provider_model_unsupported",
|
|
208
|
+
`Pi SDK could not resolve provider "${provider}" model "${modelId}". ${knownModelHint(provider)}`,
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function createOpenRouterPassThroughModel(modelId: string): Model<"openai-completions"> {
|
|
213
|
+
return {
|
|
214
|
+
id: modelId,
|
|
215
|
+
name: `OpenRouter ${modelId}`,
|
|
216
|
+
api: "openai-completions",
|
|
217
|
+
provider: "openrouter",
|
|
218
|
+
baseUrl: OPENROUTER_BASE_URL,
|
|
219
|
+
reasoning: false,
|
|
220
|
+
input: ["text"],
|
|
221
|
+
cost: {
|
|
222
|
+
input: 0,
|
|
223
|
+
output: 0,
|
|
224
|
+
cacheRead: 0,
|
|
225
|
+
cacheWrite: 0,
|
|
226
|
+
},
|
|
227
|
+
contextWindow: UNKNOWN_OPENROUTER_CONTEXT_WINDOW,
|
|
228
|
+
maxTokens: UNKNOWN_OPENROUTER_MAX_TOKENS,
|
|
229
|
+
compat: {
|
|
230
|
+
openRouterRouting: {},
|
|
231
|
+
},
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
function knownModelHint(provider: Provider): string {
|
|
236
|
+
const examples = getModels(provider as any)
|
|
237
|
+
.slice(0, 5)
|
|
238
|
+
.map((model) => model.id);
|
|
239
|
+
|
|
240
|
+
if (examples.length === 0) {
|
|
241
|
+
return "Use a model id supported by the installed Pi SDK for that provider.";
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
return `Use a model id supported by the installed Pi SDK for that provider. Examples: ${examples.join(", ")}.`;
|
|
211
245
|
}
|
|
212
246
|
|
|
213
247
|
function toPiMessages(messages: ProviderRunInput["messages"]): Message[] {
|