@kalphq/cli 0.0.0-dev-20260416063606 → 0.0.0-dev-20260416083945

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 (61) hide show
  1. package/dist/{chunk-FBVCQTQN.js → chunk-AME2JH3Z.js} +90 -7
  2. package/dist/chunk-AME2JH3Z.js.map +1 -0
  3. package/dist/chunk-LAKPXKSS.js +37 -0
  4. package/dist/chunk-LAKPXKSS.js.map +1 -0
  5. package/dist/create-445EVHYA.js +71 -0
  6. package/dist/create-445EVHYA.js.map +1 -0
  7. package/dist/index.js +56 -3
  8. package/dist/index.js.map +1 -1
  9. package/dist/{init-FLJXMJQZ.js → init-O7CMWTZ6.js} +23 -36
  10. package/dist/init-O7CMWTZ6.js.map +1 -0
  11. package/dist/link-V3ZDZKDE.js +22 -0
  12. package/dist/link-V3ZDZKDE.js.map +1 -0
  13. package/dist/login-NLTYFJL7.js +26 -0
  14. package/dist/login-NLTYFJL7.js.map +1 -0
  15. package/dist/logout-6ZYZGGVI.js +26 -0
  16. package/dist/logout-6ZYZGGVI.js.map +1 -0
  17. package/dist/push-RUBMCAYR.js +103 -0
  18. package/dist/push-RUBMCAYR.js.map +1 -0
  19. package/package.json +5 -3
  20. package/templates/agents/b2b-sales/index.ts +32 -3
  21. package/templates/agents/b2b-sales/signals/deal-won.ts +31 -0
  22. package/templates/agents/b2b-sales/signals/hot-lead-alert.ts +29 -0
  23. package/templates/agents/b2b-sales/steps/qualify-prospect.ts +50 -0
  24. package/templates/agents/b2b-sales/tools/send-slack-notification.ts +26 -0
  25. package/templates/agents/b2b-sales/webhooks/crm-inbound.ts +27 -0
  26. package/templates/agents/b2b-sales/webhooks/stripe-payment.ts +27 -0
  27. package/templates/agents/customer-support/index.ts +37 -5
  28. package/templates/agents/customer-support/signals/escalation-needed.ts +28 -0
  29. package/templates/agents/customer-support/signals/ticket-resolved.ts +29 -0
  30. package/templates/agents/customer-support/steps/escalate-ticket.ts +53 -0
  31. package/templates/agents/customer-support/tools/create-jira-issue.ts +30 -0
  32. package/templates/agents/customer-support/webhooks/slack-escalation.ts +27 -0
  33. package/templates/agents/customer-support/webhooks/zendesk-ticket.ts +29 -0
  34. package/templates/agents/financial-agent/index.ts +24 -2
  35. package/templates/agents/financial-agent/signals/market-alert.ts +31 -0
  36. package/templates/agents/financial-agent/signals/portfolio-rebalance.ts +27 -0
  37. package/templates/agents/financial-agent/steps/rebalance-check.ts +55 -0
  38. package/templates/agents/financial-agent/tools/send-email-alert.ts +31 -0
  39. package/templates/agents/financial-agent/webhooks/exchange-webhook.ts +33 -0
  40. package/templates/agents/financial-agent/webhooks/tradingview-alert.ts +30 -0
  41. package/templates/agents/minimal/index.ts +10 -2
  42. package/templates/agents/minimal/signals/error-alert.ts +26 -0
  43. package/templates/agents/minimal/signals/task-complete.ts +25 -0
  44. package/templates/agents/minimal/steps/transform-data.ts +32 -0
  45. package/templates/agents/minimal/tools/http-request.ts +26 -0
  46. package/templates/agents/minimal/webhooks/generic-inbound.ts +25 -0
  47. package/templates/agents/minimal/webhooks/health-check.ts +23 -0
  48. package/dist/build-2V4OQ3G3.js +0 -122
  49. package/dist/build-2V4OQ3G3.js.map +0 -1
  50. package/dist/chunk-FBVCQTQN.js.map +0 -1
  51. package/dist/create-AMCRXGOA.js +0 -116
  52. package/dist/create-AMCRXGOA.js.map +0 -1
  53. package/dist/init-FLJXMJQZ.js.map +0 -1
  54. package/templates/agents/b2b-sales/signals/.gitkeep +0 -0
  55. package/templates/agents/b2b-sales/webhooks/.gitkeep +0 -0
  56. package/templates/agents/customer-support/signals/.gitkeep +0 -0
  57. package/templates/agents/customer-support/webhooks/.gitkeep +0 -0
  58. package/templates/agents/financial-agent/signals/.gitkeep +0 -0
  59. package/templates/agents/financial-agent/webhooks/.gitkeep +0 -0
  60. package/templates/agents/minimal/signals/.gitkeep +0 -0
  61. package/templates/agents/minimal/webhooks/.gitkeep +0 -0
@@ -0,0 +1,103 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ ensureConfig
4
+ } from "./chunk-LAKPXKSS.js";
5
+
6
+ // src/commands/push.ts
7
+ import { join } from "path";
8
+ import { readFile } from "fs/promises";
9
+ import { defineCommand } from "citty";
10
+ import * as p from "@clack/prompts";
11
+ import pc from "picocolors";
12
+ var LOGO = "\u{1F98B}";
13
+ var push_default = defineCommand({
14
+ meta: { name: "push", description: "Push an agent to Kalp (preview mode)" },
15
+ args: {
16
+ agent: {
17
+ type: "string",
18
+ alias: "a",
19
+ description: "Agent name to push",
20
+ required: false
21
+ }
22
+ },
23
+ async run({ args }) {
24
+ const cwd = process.cwd();
25
+ p.intro(`${LOGO} ${pc.bold("kalp push")}`);
26
+ const agentName = args.agent;
27
+ if (!agentName) {
28
+ p.log.error(`Missing required flag ${pc.cyan("-a <agent-name>")}`);
29
+ p.outro(pc.dim(`Example: ${pc.cyan("kalp push -a my-agent")}`));
30
+ process.exit(1);
31
+ }
32
+ try {
33
+ await ensureConfig(cwd);
34
+ } catch {
35
+ p.log.error(`${pc.cyan("kalp.config.ts")} not found`);
36
+ p.outro(pc.dim(`Run ${pc.cyan("kalp init")} first.`));
37
+ process.exit(1);
38
+ }
39
+ const agentPath = join(cwd, "agents", agentName, "index.ts");
40
+ let agentCode;
41
+ try {
42
+ agentCode = await readFile(agentPath, "utf-8");
43
+ } catch {
44
+ p.log.error(
45
+ `Agent ${pc.cyan(agentName)} not found at ${pc.cyan(`agents/${agentName}/index.ts`)}`
46
+ );
47
+ process.exit(1);
48
+ }
49
+ const s = p.spinner();
50
+ s.start(`Parsing agent ${pc.cyan(agentName)}`);
51
+ const defineAgentMatch = agentCode.match(
52
+ /defineAgent\(\s*(\{[\s\S]*?\})\s*\)/
53
+ );
54
+ if (!defineAgentMatch?.[1]) {
55
+ s.stop(pc.red("Could not parse defineAgent call"));
56
+ process.exit(1);
57
+ }
58
+ const stepMatches = [
59
+ ...agentCode.matchAll(/createStep\(\s*(\{[\s\S]*?\})\s*\)/g)
60
+ ];
61
+ const toolMatches = [
62
+ ...agentCode.matchAll(/createTool\(\s*(\{[\s\S]*?\})\s*\)/g)
63
+ ];
64
+ const steps = stepMatches.map((match, i) => {
65
+ const content = match[1] ?? "";
66
+ const idMatch = content.match(/id:\s*["']([^"']+)["']/);
67
+ const descMatch = content.match(/description:\s*["']([^"']+)["']/);
68
+ return {
69
+ id: idMatch?.[1] ?? `step_${i}`,
70
+ description: descMatch?.[1] ?? ""
71
+ };
72
+ });
73
+ const tools = toolMatches.map((match, i) => {
74
+ const content = match[1] ?? "";
75
+ const idMatch = content.match(/id:\s*["']([^"']+)["']/);
76
+ const descMatch = content.match(/description:\s*["']([^"']+)["']/);
77
+ return {
78
+ id: idMatch?.[1] ?? `tool_${i}`,
79
+ description: descMatch?.[1] ?? ""
80
+ };
81
+ });
82
+ const agentConfig = {
83
+ name: agentName,
84
+ source: agentPath,
85
+ steps,
86
+ tools
87
+ // Future: full AST parsing with Zod schema extraction
88
+ };
89
+ s.stop("Agent parsed");
90
+ console.log("\n" + pc.dim("\u2500".repeat(50)));
91
+ console.log(pc.cyan("Agent Configuration (JSON):"));
92
+ console.log(pc.dim("\u2500".repeat(50)));
93
+ console.log(JSON.stringify(agentConfig, null, 2));
94
+ console.log(pc.dim("\u2500".repeat(50)) + "\n");
95
+ p.outro(
96
+ `${LOGO} ${pc.green("Preview ready")} ${pc.dim("\u2014 push to deploy coming soon")}`
97
+ );
98
+ }
99
+ });
100
+ export {
101
+ push_default as default
102
+ };
103
+ //# sourceMappingURL=push-RUBMCAYR.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/push.ts"],"sourcesContent":["import { join } from \"node:path\";\nimport { readFile } from \"node:fs/promises\";\nimport { defineCommand } from \"citty\";\nimport * as p from \"@clack/prompts\";\nimport pc from \"picocolors\";\nimport { ensureConfig } from \"../utils/fs.js\";\n\nconst LOGO = \"🦋\";\n\nexport default defineCommand({\n meta: { name: \"push\", description: \"Push an agent to Kalp (preview mode)\" },\n args: {\n agent: {\n type: \"string\",\n alias: \"a\",\n description: \"Agent name to push\",\n required: false,\n },\n },\n async run({ args }) {\n const cwd = process.cwd();\n\n p.intro(`${LOGO} ${pc.bold(\"kalp push\")}`);\n\n // ── Validate agent name ─────────────────────────────────────────────────\n const agentName = args.agent;\n if (!agentName) {\n p.log.error(`Missing required flag ${pc.cyan(\"-a <agent-name>\")}`);\n p.outro(pc.dim(`Example: ${pc.cyan(\"kalp push -a my-agent\")}`));\n process.exit(1);\n }\n\n // ── Validate kalp.config.ts exists ─────────────────────────────────────\n try {\n await ensureConfig(cwd);\n } catch {\n p.log.error(`${pc.cyan(\"kalp.config.ts\")} not found`);\n p.outro(pc.dim(`Run ${pc.cyan(\"kalp init\")} first.`));\n process.exit(1);\n }\n\n // ── Find agent ──────────────────────────────────────────────────────────\n const agentPath = join(cwd, \"agents\", agentName, \"index.ts\");\n let agentCode: string;\n try {\n agentCode = await readFile(agentPath, \"utf-8\");\n } catch {\n p.log.error(\n `Agent ${pc.cyan(agentName)} not found at ${pc.cyan(`agents/${agentName}/index.ts`)}`,\n );\n process.exit(1);\n }\n\n const s = p.spinner();\n s.start(`Parsing agent ${pc.cyan(agentName)}`);\n\n // ── Parse agent config from TypeScript ──────────────────────────────────\n // Extract defineAgent({...}) call using regex\n const defineAgentMatch = agentCode.match(\n /defineAgent\\(\\s*(\\{[\\s\\S]*?\\})\\s*\\)/,\n );\n if (!defineAgentMatch?.[1]) {\n s.stop(pc.red(\"Could not parse defineAgent call\"));\n process.exit(1);\n }\n\n // Extract steps and tools arrays for schema generation\n const stepMatches = [\n ...agentCode.matchAll(/createStep\\(\\s*(\\{[\\s\\S]*?\\})\\s*\\)/g),\n ];\n const toolMatches = [\n ...agentCode.matchAll(/createTool\\(\\s*(\\{[\\s\\S]*?\\})\\s*\\)/g),\n ];\n\n const steps = stepMatches.map((match, i) => {\n const content = match[1] ?? \"\";\n const idMatch = content.match(/id:\\s*[\"']([^\"']+)[\"']/);\n const descMatch = content.match(/description:\\s*[\"']([^\"']+)[\"']/);\n return {\n id: idMatch?.[1] ?? `step_${i}`,\n description: descMatch?.[1] ?? \"\",\n };\n });\n\n const tools = toolMatches.map((match, i) => {\n const content = match[1] ?? \"\";\n const idMatch = content.match(/id:\\s*[\"']([^\"']+)[\"']/);\n const descMatch = content.match(/description:\\s*[\"']([^\"']+)[\"']/);\n return {\n id: idMatch?.[1] ?? `tool_${i}`,\n description: descMatch?.[1] ?? \"\",\n };\n });\n\n // ── Build JSON representation ───────────────────────────────────────────\n const agentConfig = {\n name: agentName,\n source: agentPath,\n steps,\n tools,\n // Future: full AST parsing with Zod schema extraction\n };\n\n s.stop(\"Agent parsed\");\n\n // ── Output JSON ─────────────────────────────────────────────────────────\n console.log(\"\\n\" + pc.dim(\"─\".repeat(50)));\n console.log(pc.cyan(\"Agent Configuration (JSON):\"));\n console.log(pc.dim(\"─\".repeat(50)));\n console.log(JSON.stringify(agentConfig, null, 2));\n console.log(pc.dim(\"─\".repeat(50)) + \"\\n\");\n\n p.outro(\n `${LOGO} ${pc.green(\"Preview ready\")} ${pc.dim(\"— push to deploy coming soon\")}`,\n );\n },\n});\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kalphq/cli",
3
- "version": "0.0.0-dev-20260416063606",
3
+ "version": "0.0.0-dev-20260416083945",
4
4
  "description": "Zero-config CLI for deploying Kalp agents",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -17,14 +17,16 @@
17
17
  "access": "public"
18
18
  },
19
19
  "dependencies": {
20
+ "@antfu/ni": "^24.4.0",
20
21
  "@clack/prompts": "^0.9.1",
21
22
  "citty": "^0.1.6",
22
23
  "esbuild": "^0.25.0",
23
24
  "giget": "^1.2.3",
24
- "nypm": "^0.3.12",
25
25
  "picocolors": "^1.1.1",
26
+ "prettier": "^3.3.3",
26
27
  "zod": "^3.25.76",
27
- "@kalphq/sdk": "0.0.0-dev-20260416063606"
28
+ "zod-to-json-schema": "^3.25.76",
29
+ "@kalphq/sdk": "0.0.0-dev-20260416083945"
28
30
  },
29
31
  "devDependencies": {
30
32
  "@types/node": "^22.15.3",
@@ -1,13 +1,21 @@
1
1
  import { asAgentId, defineAgent } from "@kalphq/sdk";
2
2
  import { scoreLead } from "./steps/score-lead.js";
3
+ import { qualifyProspect } from "./steps/qualify-prospect.js";
3
4
  import { enrichCompany } from "./tools/enrich-company.js";
5
+ import { sendSlackNotification } from "./tools/send-slack-notification.js";
6
+ import { crmInbound } from "./webhooks/crm-inbound.js";
7
+ import { stripePayment } from "./webhooks/stripe-payment.js";
8
+ import { hotLeadAlert } from "./signals/hot-lead-alert.js";
9
+ import { dealWon } from "./signals/deal-won.js";
4
10
 
5
11
  export default defineAgent({
6
12
  id: asAgentId("__AGENT_NAME__"),
7
13
  name: "__AGENT_NAME__",
8
14
  description: "Automates B2B outreach with lead scoring and CRM enrichment.",
9
- steps: [scoreLead],
10
- tools: [enrichCompany],
15
+ steps: [scoreLead, qualifyProspect],
16
+ tools: [enrichCompany, sendSlackNotification],
17
+ webhooks: [crmInbound, stripePayment],
18
+ signals: [hotLeadAlert, dealWon],
11
19
 
12
20
  systemPrompt:
13
21
  "You are a B2B sales assistant. Score leads, enrich company data, and draft personalized outreach messages.",
@@ -19,10 +27,31 @@ export default defineAgent({
19
27
  return { text: "Lead score too low — skipping outreach." };
20
28
  }
21
29
 
30
+ // Qualify the prospect
31
+ const qualified = await ctx.runStep(qualifyProspect, {
32
+ company: message.text,
33
+ score: lead.score,
34
+ domain: lead.domain,
35
+ });
36
+
37
+ if (!qualified.qualified) {
38
+ return { text: `Prospect not qualified: ${qualified.reason}` };
39
+ }
40
+
22
41
  const enriched = await ctx.callTool(enrichCompany, { domain: lead.domain });
23
42
 
43
+ // Notify for high-priority leads
44
+ if (qualified.priority === "high") {
45
+ await ctx.callTool(sendSlackNotification, {
46
+ company: message.text,
47
+ score: lead.score,
48
+ domain: lead.domain,
49
+ channel: "sales-alerts",
50
+ });
51
+ }
52
+
24
53
  return {
25
- text: `${enriched.companyName} (${lead.score}/100) — Ready for outreach.`,
54
+ text: `${enriched.companyName} (${lead.score}/100, ${qualified.priority} priority) — Ready for outreach.`,
26
55
  };
27
56
  },
28
57
  });
@@ -0,0 +1,31 @@
1
+ import { createSignal } from "@kalphq/sdk";
2
+ import { z } from "zod";
3
+
4
+ /**
5
+ * Signal sent when a deal is won for commission tracking
6
+ */
7
+ export const dealWon = createSignal({
8
+ id: "deal_won",
9
+ input: z.object({
10
+ customerId: z.string(),
11
+ leadId: z.string().optional(),
12
+ amount: z.number().optional(),
13
+ currency: z.string(),
14
+ source: z.string(),
15
+ repId: z.string().optional(),
16
+ }),
17
+ async handler({ customerId, leadId, amount, currency, source, repId }) {
18
+ // Signal received - in real implementation this would:
19
+ // - Update CRM with deal status
20
+ // - Notify sales manager
21
+ // - Track commission for rep
22
+ return {
23
+ recorded: true,
24
+ dealId: leadId ?? customerId,
25
+ amount,
26
+ currency,
27
+ source,
28
+ commissionRep: repId,
29
+ };
30
+ },
31
+ });
@@ -0,0 +1,29 @@
1
+ import { createSignal } from "@kalphq/sdk";
2
+ import { z } from "zod";
3
+
4
+ /**
5
+ * Signal broadcast when a hot lead is identified
6
+ */
7
+ export const hotLeadAlert = createSignal({
8
+ id: "hot_lead_alert",
9
+ input: z.object({
10
+ leadId: z.string(),
11
+ company: z.string(),
12
+ score: z.number(),
13
+ email: z.string(),
14
+ priority: z.string(), // "high", "medium", "low"
15
+ qualified: z.boolean(),
16
+ }),
17
+ async handler({ leadId, company, score, email, priority, qualified }) {
18
+ // Signal received by other agents (SalesManager, NotificationAgent, etc.)
19
+ // In real implementation, this would trigger notifications
20
+ return {
21
+ acknowledged: true,
22
+ leadId,
23
+ company,
24
+ score,
25
+ priority,
26
+ qualified,
27
+ };
28
+ },
29
+ });
@@ -0,0 +1,50 @@
1
+ import { createStep } from "@kalphq/sdk";
2
+ import { z } from "zod";
3
+
4
+ export const qualifyProspect = createStep({
5
+ id: "qualify_prospect",
6
+ description:
7
+ "Deep qualification of prospects based on lead score and company data.",
8
+ input: z.object({
9
+ company: z.string(),
10
+ score: z.number(),
11
+ domain: z.string(),
12
+ }),
13
+ output: z.object({
14
+ qualified: z.boolean(),
15
+ reason: z.string(),
16
+ priority: z.string(), // "high" | "medium" | "low"
17
+ }),
18
+ async run({ company, score, domain }, ctx) {
19
+ ctx.logger.info("Qualifying prospect", { company, score, domain });
20
+
21
+ // Auto-qualify high scores
22
+ if (score >= 80) {
23
+ return {
24
+ qualified: true,
25
+ reason: "High engagement score indicates strong interest",
26
+ priority: "high",
27
+ };
28
+ }
29
+
30
+ // Qualify medium scores with domain check
31
+ if (score >= 50) {
32
+ const isEnterprise =
33
+ domain.includes("enterprise") || domain.endsWith(".corp");
34
+ return {
35
+ qualified: isEnterprise,
36
+ reason: isEnterprise
37
+ ? "Enterprise domain with decent engagement"
38
+ : "Score too low for non-enterprise domain",
39
+ priority: isEnterprise ? "medium" : "low",
40
+ };
41
+ }
42
+
43
+ // Low scores - not qualified
44
+ return {
45
+ qualified: false,
46
+ reason: "Low engagement score",
47
+ priority: "low",
48
+ };
49
+ },
50
+ });
@@ -0,0 +1,26 @@
1
+ import { createTool } from "@kalphq/sdk";
2
+ import { z } from "zod";
3
+
4
+ export const sendSlackNotification = createTool({
5
+ id: "send_slack_notification",
6
+ description: "Sends a notification to Slack channel for hot leads.",
7
+ input: z.object({
8
+ company: z.string(),
9
+ score: z.number(),
10
+ domain: z.string(),
11
+ channel: z.string().default("#sales-hot-leads"),
12
+ }),
13
+ async execute({ company, score, domain, channel }, ctx) {
14
+ ctx.logger.info("Sending Slack notification", { company, score, channel });
15
+
16
+ // Replace with actual Slack API call using webhook or bot token
17
+ // Example: await fetch("https://hooks.slack.com/services/...", {...})
18
+
19
+ return {
20
+ sent: true,
21
+ channel,
22
+ message: `🔥 Hot Lead Alert: ${company} (${domain}) scored ${score}/100`,
23
+ timestamp: new Date().toISOString(),
24
+ };
25
+ },
26
+ });
@@ -0,0 +1,27 @@
1
+ import { defineWebhook } from "@kalphq/sdk";
2
+ import { z } from "zod";
3
+
4
+ /**
5
+ * Inbound webhook to receive new lead events from CRM (HubSpot, Salesforce, etc.)
6
+ */
7
+ export const crmInbound = defineWebhook({
8
+ id: "crm_inbound",
9
+ input: z.object({
10
+ leadId: z.string(),
11
+ email: z.string().email(),
12
+ company: z.string(),
13
+ source: z.string(),
14
+ metadata: z.record(z.unknown()).optional(),
15
+ }),
16
+ async handler({ leadId, email, company, source }) {
17
+ // Process new lead from CRM
18
+ // In real implementation, this would trigger agent processing
19
+ return {
20
+ success: true,
21
+ message: "Lead received",
22
+ leadId,
23
+ company,
24
+ source,
25
+ };
26
+ },
27
+ });
@@ -0,0 +1,27 @@
1
+ import { defineWebhook } from "@kalphq/sdk";
2
+ import { z } from "zod";
3
+
4
+ /**
5
+ * Stripe webhook for payment events - tracks trial conversions and payments
6
+ */
7
+ export const stripePayment = defineWebhook({
8
+ id: "stripe_payment",
9
+ input: z.object({
10
+ type: z.string(), // "payment_intent.succeeded", "invoice.paid", etc.
11
+ customerId: z.string(),
12
+ amount: z.number().optional(),
13
+ currency: z.string().default("usd"),
14
+ metadata: z.record(z.unknown()).optional(),
15
+ }),
16
+ async handler({ type, customerId, amount, currency }) {
17
+ // Process Stripe payment event
18
+ // In real implementation, this would update CRM and notify agents
19
+ return {
20
+ received: true,
21
+ eventType: type,
22
+ customerId,
23
+ amount,
24
+ currency,
25
+ };
26
+ },
27
+ });
@@ -1,13 +1,21 @@
1
1
  import { asAgentId, defineAgent } from "@kalphq/sdk";
2
2
  import { classifyTicket } from "./steps/classify-ticket.js";
3
+ import { escalateTicket } from "./steps/escalate-ticket.js";
3
4
  import { searchKnowledgeBase } from "./tools/search-kb.js";
5
+ import { createJiraIssue } from "./tools/create-jira-issue.js";
6
+ import { slackEscalation } from "./webhooks/slack-escalation.js";
7
+ import { zendeskTicket } from "./webhooks/zendesk-ticket.js";
8
+ import { escalationNeeded } from "./signals/escalation-needed.js";
9
+ import { ticketResolved } from "./signals/ticket-resolved.js";
4
10
 
5
11
  export default defineAgent({
6
12
  id: asAgentId("__AGENT_NAME__"),
7
13
  name: "__AGENT_NAME__",
8
14
  description: "Handles incoming support tickets with AI-powered routing.",
9
- steps: [classifyTicket],
10
- tools: [searchKnowledgeBase],
15
+ steps: [classifyTicket, escalateTicket],
16
+ tools: [searchKnowledgeBase, createJiraIssue],
17
+ webhooks: [slackEscalation, zendeskTicket],
18
+ signals: [escalationNeeded, ticketResolved],
11
19
 
12
20
  systemPrompt:
13
21
  "You are a friendly support agent. Classify tickets, search the knowledge base, and resolve issues efficiently.",
@@ -15,14 +23,38 @@ export default defineAgent({
15
23
  async onMessage(message, ctx) {
16
24
  const ticket = await ctx.runStep(classifyTicket, { text: message.text });
17
25
 
18
- if (ticket.category === "billing") {
19
- return { text: "Routing to billing team..." };
26
+ // Check if escalation is needed
27
+ const escalation = await ctx.runStep(escalateTicket, {
28
+ category: ticket.category,
29
+ priority: ticket.priority,
30
+ sentiment: "neutral", // Could be detected from message
31
+ previousAttempts: 0,
32
+ });
33
+
34
+ if (escalation.escalate) {
35
+ // Create Jira issue for technical problems
36
+ if (ticket.category === "technical") {
37
+ const jira = await ctx.callTool(createJiraIssue, {
38
+ summary: `Support Ticket: ${message.text.slice(0, 50)}...`,
39
+ description: message.text,
40
+ priority: ticket.priority,
41
+ reporter: "support-agent",
42
+ });
43
+ return {
44
+ text: `Escalated to engineering team. Issue: ${jira.issueKey}`,
45
+ };
46
+ }
47
+
48
+ return {
49
+ text: `Escalating to ${escalation.assignTo}: ${escalation.reason}`,
50
+ };
20
51
  }
21
52
 
53
+ // Try knowledge base for non-escalated issues
22
54
  const results = await ctx.callTool(searchKnowledgeBase, {
23
55
  query: message.text,
24
56
  });
25
57
 
26
- return { text: results.answer ?? "Let me escalate this to a human agent." };
58
+ return { text: results.answer ?? "Let me connect you with a specialist." };
27
59
  },
28
60
  });
@@ -0,0 +1,28 @@
1
+ import { createSignal } from "@kalphq/sdk";
2
+ import { z } from "zod";
3
+
4
+ /**
5
+ * Signal to alert senior support agents about escalation
6
+ */
7
+ export const escalationNeeded = createSignal({
8
+ id: "escalation_needed",
9
+ input: z.object({
10
+ ticketId: z.string(),
11
+ customerId: z.string(),
12
+ issue: z.string(),
13
+ priority: z.string(),
14
+ previousAttempts: z.number(),
15
+ sentiment: z.string(),
16
+ }),
17
+ async handler({ ticketId, customerId, issue, priority, previousAttempts, sentiment }) {
18
+ // Signal received by senior support agents
19
+ // In real implementation, this triggers notifications
20
+
21
+ return {
22
+ received: true,
23
+ ticketId,
24
+ assignedTier: priority === "high" ? "tier3" : "tier2",
25
+ estimatedHandleTime: priority === "high" ? "15 min" : "1 hour",
26
+ };
27
+ },
28
+ });
@@ -0,0 +1,29 @@
1
+ import { createSignal } from "@kalphq/sdk";
2
+ import { z } from "zod";
3
+
4
+ /**
5
+ * Signal broadcast when a ticket is resolved
6
+ */
7
+ export const ticketResolved = createSignal({
8
+ id: "ticket_resolved",
9
+ input: z.object({
10
+ ticketId: z.string(),
11
+ customerId: z.string(),
12
+ resolution: z.string(),
13
+ satisfaction: z.string(), // "positive", "neutral", "negative"
14
+ resolutionTime: z.number(), // minutes
15
+ }),
16
+ async handler({ ticketId, customerId, resolution, satisfaction, resolutionTime }) {
17
+ // Broadcast resolution for analytics and notifications
18
+ // In real implementation, update dashboards and notify customer
19
+
20
+ return {
21
+ recorded: true,
22
+ ticketId,
23
+ customerId,
24
+ satisfaction,
25
+ resolutionTime,
26
+ timestamp: new Date().toISOString(),
27
+ };
28
+ },
29
+ });
@@ -0,0 +1,53 @@
1
+ import { createStep } from "@kalphq/sdk";
2
+ import { z } from "zod";
3
+
4
+ export const escalateTicket = createStep({
5
+ id: "escalate_ticket",
6
+ description: "Determines if a ticket should be escalated to human support.",
7
+ input: z.object({
8
+ category: z.string(), // "billing", "technical", "general"
9
+ priority: z.string(), // "low", "medium", "high"
10
+ sentiment: z.string(), // "frustrated", "angry", "neutral", "satisfied"
11
+ previousAttempts: z.number().default(0),
12
+ }),
13
+ output: z.object({
14
+ escalate: z.boolean(),
15
+ reason: z.string(),
16
+ assignTo: z.string(), // "tier1", "tier2", "tier3", "human"
17
+ }),
18
+ async run({ category, priority, sentiment, previousAttempts }) {
19
+ // Auto-escalate frustrated/angry customers with technical issues
20
+ if ((sentiment === "frustrated" || sentiment === "angry") && category === "technical") {
21
+ return {
22
+ escalate: true,
23
+ reason: "Frustrated customer with technical issue",
24
+ assignTo: "tier2",
25
+ };
26
+ }
27
+
28
+ // Escalate high priority billing issues immediately
29
+ if (priority === "high" && category === "billing") {
30
+ return {
31
+ escalate: true,
32
+ reason: "High priority billing issue",
33
+ assignTo: "tier3",
34
+ };
35
+ }
36
+
37
+ // Escalate after multiple failed attempts
38
+ if (previousAttempts >= 3) {
39
+ return {
40
+ escalate: true,
41
+ reason: `Multiple failed resolution attempts (${previousAttempts})`,
42
+ assignTo: "human",
43
+ };
44
+ }
45
+
46
+ // No escalation needed
47
+ return {
48
+ escalate: false,
49
+ reason: "Within agent capabilities",
50
+ assignTo: "tier1",
51
+ };
52
+ },
53
+ });
@@ -0,0 +1,30 @@
1
+ import { createTool } from "@kalphq/sdk";
2
+ import { z } from "zod";
3
+
4
+ export const createJiraIssue = createTool({
5
+ id: "create_jira_issue",
6
+ description: "Creates a bug ticket in Jira for technical issues requiring engineering.",
7
+ input: z.object({
8
+ summary: z.string(),
9
+ description: z.string(),
10
+ priority: z.string(), // "Low", "Medium", "High", "Critical"
11
+ component: z.string().optional(),
12
+ reporter: z.string(),
13
+ }),
14
+ async execute({ summary, description, priority, component, reporter }) {
15
+ // In real implementation, call Jira REST API
16
+ // POST /rest/api/2/issue
17
+
18
+ const issueKey = `PROJ-${Math.floor(Math.random() * 10000)}`;
19
+
20
+ return {
21
+ created: true,
22
+ issueKey,
23
+ summary,
24
+ priority,
25
+ component: component ?? "General",
26
+ reporter,
27
+ url: `https://jira.example.com/browse/${issueKey}`,
28
+ };
29
+ },
30
+ });
@@ -0,0 +1,27 @@
1
+ import { defineWebhook } from "@kalphq/sdk";
2
+ import { z } from "zod";
3
+
4
+ /**
5
+ * Webhook for Slack /escalate command or button
6
+ */
7
+ export const slackEscalation = defineWebhook({
8
+ id: "slack_escalation",
9
+ input: z.object({
10
+ userId: z.string(),
11
+ channelId: z.string(),
12
+ ticketId: z.string(),
13
+ reason: z.string(),
14
+ urgency: z.string(), // "low", "medium", "high"
15
+ }),
16
+ async handler({ userId, channelId, ticketId, reason, urgency }) {
17
+ // Process escalation request from Slack
18
+ // In real implementation, notify on-call support
19
+
20
+ return {
21
+ acknowledged: true,
22
+ ticketId,
23
+ escalationId: `ESC-${Date.now()}`,
24
+ estimatedResponse: urgency === "high" ? "5 minutes" : "30 minutes",
25
+ };
26
+ },
27
+ });
@@ -0,0 +1,29 @@
1
+ import { defineWebhook } from "@kalphq/sdk";
2
+ import { z } from "zod";
3
+
4
+ /**
5
+ * Zendesk ticket sync webhook
6
+ */
7
+ export const zendeskTicket = defineWebhook({
8
+ id: "zendesk_ticket",
9
+ input: z.object({
10
+ ticketId: z.string(),
11
+ status: z.string(), // "new", "open", "pending", "solved", "closed"
12
+ subject: z.string(),
13
+ requesterEmail: z.string(),
14
+ tags: z.array(z.string()),
15
+ customFields: z.record(z.unknown()).optional(),
16
+ }),
17
+ async handler({ ticketId, status, subject, requesterEmail, tags, customFields }) {
18
+ // Sync external Zendesk ticket with internal system
19
+ // In real implementation, update internal ticket store
20
+
21
+ return {
22
+ synced: true,
23
+ externalId: ticketId,
24
+ localId: `LOCAL-${ticketId}`,
25
+ status,
26
+ tags,
27
+ };
28
+ },
29
+ });