@tellet/create 0.8.0
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 +195 -0
- package/dist/ai/generate.d.ts +33 -0
- package/dist/ai/generate.js +108 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +337 -0
- package/dist/scaffold/project.d.ts +44 -0
- package/dist/scaffold/project.js +318 -0
- package/package.json +48 -0
- package/template/Dockerfile +35 -0
- package/template/app/(dashboard)/agents/page.tsx +14 -0
- package/template/app/(dashboard)/conversations/[id]/page.tsx +103 -0
- package/template/app/(dashboard)/conversations/page.tsx +50 -0
- package/template/app/(dashboard)/dashboard/page.tsx +102 -0
- package/template/app/(dashboard)/layout.tsx +15 -0
- package/template/app/(dashboard)/settings/page.tsx +46 -0
- package/template/app/(site)/layout.tsx +3 -0
- package/template/app/(site)/page.tsx +25 -0
- package/template/app/api/chat/route.ts +129 -0
- package/template/app/api/cron/route.ts +29 -0
- package/template/app/api/orchestrator/route.ts +139 -0
- package/template/app/globals.css +30 -0
- package/template/app/layout.tsx +18 -0
- package/template/components/chat/ChatWidget.tsx +109 -0
- package/template/components/chat/Markdown.tsx +136 -0
- package/template/components/dashboard/AgentChat.tsx +192 -0
- package/template/components/dashboard/AgentsListClient.tsx +86 -0
- package/template/components/dashboard/DashboardAgentGrid.tsx +73 -0
- package/template/components/dashboard/OrchestratorChat.tsx +251 -0
- package/template/components/dashboard/Sidebar.tsx +44 -0
- package/template/components/dashboard/StatsCards.tsx +40 -0
- package/template/components/dashboard/Welcome.tsx +139 -0
- package/template/components/sections/Agents.tsx +67 -0
- package/template/components/sections/CTA.tsx +46 -0
- package/template/components/sections/FAQ.tsx +81 -0
- package/template/components/sections/Features.tsx +51 -0
- package/template/components/sections/Footer.tsx +22 -0
- package/template/components/sections/Hero.tsx +86 -0
- package/template/components/sections/Icons.tsx +29 -0
- package/template/components/ui/Button.tsx +26 -0
- package/template/docker-compose.yml +32 -0
- package/template/infra/bin/app.ts +16 -0
- package/template/infra/cdk.json +6 -0
- package/template/infra/lib/tellet-stack.ts +216 -0
- package/template/infra/package.json +20 -0
- package/template/infra/tsconfig.json +16 -0
- package/template/lib/db.ts +37 -0
- package/template/lib/engine/default.ts +227 -0
- package/template/lib/engine/index.ts +17 -0
- package/template/lib/mcp/client.ts +97 -0
- package/template/lib/mcp/knowledge.ts +84 -0
- package/template/lib/mcp/registry.ts +106 -0
- package/template/lib/orchestrator/executor.ts +202 -0
- package/template/lib/orchestrator/tools.ts +245 -0
- package/template/lib/providers/anthropic.ts +41 -0
- package/template/lib/providers/index.ts +36 -0
- package/template/lib/providers/openai.ts +46 -0
- package/template/lib/scheduler.ts +115 -0
- package/template/lib/supabase.ts +30 -0
- package/template/lib/tellet.ts +45 -0
- package/template/lib/utils.ts +6 -0
- package/template/next.config.ts +7 -0
- package/template/public/widget.js +172 -0
- package/template/railway.toml +9 -0
- package/template/tsconfig.json +21 -0
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
import Anthropic from "@anthropic-ai/sdk";
|
|
2
|
+
import OpenAI from "openai";
|
|
3
|
+
import { getToolsForAgent, callMCPTool } from "@/lib/mcp/client";
|
|
4
|
+
import { getConfig } from "@/lib/tellet";
|
|
5
|
+
import type { AgentConfig } from "./index";
|
|
6
|
+
import type { StreamChunk } from "@/lib/providers";
|
|
7
|
+
|
|
8
|
+
interface BuiltinTool {
|
|
9
|
+
name: string;
|
|
10
|
+
description: string;
|
|
11
|
+
input_schema: Anthropic.Tool.InputSchema;
|
|
12
|
+
execute: (input: Record<string, unknown>) => Promise<string>;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface AgentStreamOptions {
|
|
16
|
+
agent: AgentConfig;
|
|
17
|
+
messages: { role: "user" | "assistant"; content: string }[];
|
|
18
|
+
builtinTools?: BuiltinTool[];
|
|
19
|
+
onToolStart?: (toolName: string) => void;
|
|
20
|
+
onToolEnd?: (toolName: string) => void;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export async function streamAgentWithTools(
|
|
24
|
+
options: AgentStreamOptions
|
|
25
|
+
): Promise<ReadableStream<StreamChunk>> {
|
|
26
|
+
const { agent, messages, builtinTools = [], onToolStart, onToolEnd } = options;
|
|
27
|
+
const config = getConfig();
|
|
28
|
+
const provider = agent.provider || config.llm.provider;
|
|
29
|
+
|
|
30
|
+
// Collect tools: builtin + MCP
|
|
31
|
+
const mcpTools = await getToolsForAgent(agent.id);
|
|
32
|
+
const allTools: Anthropic.Tool[] = [
|
|
33
|
+
...builtinTools.map((t) => ({
|
|
34
|
+
name: t.name,
|
|
35
|
+
description: t.description,
|
|
36
|
+
input_schema: t.input_schema,
|
|
37
|
+
})),
|
|
38
|
+
...mcpTools,
|
|
39
|
+
];
|
|
40
|
+
|
|
41
|
+
if (provider === "openai") {
|
|
42
|
+
return streamOpenAI(agent, messages, allTools, builtinTools);
|
|
43
|
+
}
|
|
44
|
+
return streamAnthropic(agent, messages, allTools, builtinTools, onToolStart, onToolEnd);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async function streamAnthropic(
|
|
48
|
+
agent: AgentConfig,
|
|
49
|
+
messages: { role: "user" | "assistant"; content: string }[],
|
|
50
|
+
tools: Anthropic.Tool[],
|
|
51
|
+
builtinTools: BuiltinTool[],
|
|
52
|
+
onToolStart?: (name: string) => void,
|
|
53
|
+
onToolEnd?: (name: string) => void
|
|
54
|
+
): Promise<ReadableStream<StreamChunk>> {
|
|
55
|
+
let _client: Anthropic | null = null;
|
|
56
|
+
function getClient() {
|
|
57
|
+
if (!_client) _client = new Anthropic();
|
|
58
|
+
return _client;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return new ReadableStream({
|
|
62
|
+
async start(controller) {
|
|
63
|
+
try {
|
|
64
|
+
let currentMessages: Anthropic.MessageParam[] = messages.map((m) => ({
|
|
65
|
+
role: m.role,
|
|
66
|
+
content: m.content,
|
|
67
|
+
}));
|
|
68
|
+
|
|
69
|
+
// Agentic loop
|
|
70
|
+
while (true) {
|
|
71
|
+
const hasTools = tools.length > 0;
|
|
72
|
+
const response = await getClient().messages.create({
|
|
73
|
+
model: agent.model,
|
|
74
|
+
max_tokens: 2048,
|
|
75
|
+
system: agent.systemPrompt,
|
|
76
|
+
messages: currentMessages,
|
|
77
|
+
...(hasTools ? { tools } : {}),
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
let hasToolUse = false;
|
|
81
|
+
const toolResults: Anthropic.ToolResultBlockParam[] = [];
|
|
82
|
+
|
|
83
|
+
for (const block of response.content) {
|
|
84
|
+
if (block.type === "text" && block.text) {
|
|
85
|
+
controller.enqueue({ text: block.text });
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (block.type === "tool_use") {
|
|
89
|
+
hasToolUse = true;
|
|
90
|
+
onToolStart?.(block.name);
|
|
91
|
+
|
|
92
|
+
let result: string;
|
|
93
|
+
const builtin = builtinTools.find((t) => t.name === block.name);
|
|
94
|
+
if (builtin) {
|
|
95
|
+
result = await builtin.execute(block.input as Record<string, unknown>);
|
|
96
|
+
} else {
|
|
97
|
+
result = await callMCPTool(block.name, block.input as Record<string, unknown>);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
onToolEnd?.(block.name);
|
|
101
|
+
toolResults.push({
|
|
102
|
+
type: "tool_result",
|
|
103
|
+
tool_use_id: block.id,
|
|
104
|
+
content: result,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (!hasToolUse) break;
|
|
110
|
+
|
|
111
|
+
currentMessages = [
|
|
112
|
+
...currentMessages,
|
|
113
|
+
{ role: "assistant", content: response.content },
|
|
114
|
+
{ role: "user", content: toolResults },
|
|
115
|
+
];
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
controller.close();
|
|
119
|
+
} catch (err) {
|
|
120
|
+
controller.enqueue({
|
|
121
|
+
text: `Error: ${err instanceof Error ? err.message : "Agent failed"}`,
|
|
122
|
+
});
|
|
123
|
+
controller.close();
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
async function streamOpenAI(
|
|
130
|
+
agent: AgentConfig,
|
|
131
|
+
messages: { role: "user" | "assistant"; content: string }[],
|
|
132
|
+
tools: Anthropic.Tool[],
|
|
133
|
+
builtinTools: BuiltinTool[]
|
|
134
|
+
): Promise<ReadableStream<StreamChunk>> {
|
|
135
|
+
let _client: OpenAI | null = null;
|
|
136
|
+
function getClient() {
|
|
137
|
+
if (!_client) _client = new OpenAI();
|
|
138
|
+
return _client;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Convert Anthropic tool format to OpenAI
|
|
142
|
+
const openaiTools: OpenAI.ChatCompletionTool[] = tools.map((t) => ({
|
|
143
|
+
type: "function" as const,
|
|
144
|
+
function: {
|
|
145
|
+
name: t.name,
|
|
146
|
+
description: t.description || "",
|
|
147
|
+
parameters: t.input_schema as Record<string, unknown>,
|
|
148
|
+
},
|
|
149
|
+
}));
|
|
150
|
+
|
|
151
|
+
return new ReadableStream({
|
|
152
|
+
async start(controller) {
|
|
153
|
+
try {
|
|
154
|
+
let currentMessages: OpenAI.ChatCompletionMessageParam[] = [
|
|
155
|
+
{ role: "system", content: agent.systemPrompt },
|
|
156
|
+
...messages.map((m) => ({
|
|
157
|
+
role: m.role as "user" | "assistant",
|
|
158
|
+
content: m.content,
|
|
159
|
+
})),
|
|
160
|
+
];
|
|
161
|
+
|
|
162
|
+
while (true) {
|
|
163
|
+
const hasTools = openaiTools.length > 0;
|
|
164
|
+
const response = await getClient().chat.completions.create({
|
|
165
|
+
model: agent.model,
|
|
166
|
+
max_tokens: 2048,
|
|
167
|
+
messages: currentMessages,
|
|
168
|
+
...(hasTools ? { tools: openaiTools } : {}),
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
const choice = response.choices[0];
|
|
172
|
+
if (!choice) break;
|
|
173
|
+
|
|
174
|
+
if (choice.message.content) {
|
|
175
|
+
controller.enqueue({ text: choice.message.content });
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (choice.finish_reason === "tool_calls" && choice.message.tool_calls) {
|
|
179
|
+
const toolMessages: OpenAI.ChatCompletionMessageParam[] = [
|
|
180
|
+
{ role: "assistant" as const, tool_calls: choice.message.tool_calls, content: choice.message.content },
|
|
181
|
+
];
|
|
182
|
+
|
|
183
|
+
for (const call of choice.message.tool_calls) {
|
|
184
|
+
if (call.type !== "function") continue;
|
|
185
|
+
const fn = call as OpenAI.ChatCompletionMessageToolCall & { type: "function"; function: { name: string; arguments: string } };
|
|
186
|
+
const input = JSON.parse(fn.function.arguments);
|
|
187
|
+
const builtin = builtinTools.find((t) => t.name === fn.function.name);
|
|
188
|
+
let result: string;
|
|
189
|
+
|
|
190
|
+
if (builtin) {
|
|
191
|
+
result = await builtin.execute(input);
|
|
192
|
+
} else {
|
|
193
|
+
result = await callMCPTool(fn.function.name, input);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
toolMessages.push({
|
|
197
|
+
role: "tool" as const,
|
|
198
|
+
tool_call_id: call.id,
|
|
199
|
+
content: result,
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
currentMessages = [...currentMessages, ...toolMessages];
|
|
204
|
+
continue;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
break;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
controller.close();
|
|
211
|
+
} catch (err) {
|
|
212
|
+
controller.enqueue({
|
|
213
|
+
text: `Error: ${err instanceof Error ? err.message : "Agent failed"}`,
|
|
214
|
+
});
|
|
215
|
+
controller.close();
|
|
216
|
+
}
|
|
217
|
+
},
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// Legacy simple stream (no tools)
|
|
222
|
+
export async function streamAgent(
|
|
223
|
+
agent: AgentConfig,
|
|
224
|
+
messages: { role: "user" | "assistant"; content: string }[]
|
|
225
|
+
) {
|
|
226
|
+
return streamAgentWithTools({ agent, messages });
|
|
227
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface AgentConfig {
|
|
2
|
+
id: string;
|
|
3
|
+
name: string;
|
|
4
|
+
role: string;
|
|
5
|
+
model: string;
|
|
6
|
+
provider?: string;
|
|
7
|
+
systemPrompt: string;
|
|
8
|
+
channels: string[];
|
|
9
|
+
tools: string[];
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function defineAgent(config: AgentConfig): AgentConfig {
|
|
13
|
+
return config;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export { streamAgent, streamAgentWithTools } from "./default";
|
|
17
|
+
export type { AgentStreamOptions } from "./default";
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
2
|
+
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
3
|
+
import { getConfig } from "@/lib/tellet";
|
|
4
|
+
import type Anthropic from "@anthropic-ai/sdk";
|
|
5
|
+
|
|
6
|
+
interface MCPConnection {
|
|
7
|
+
client: Client;
|
|
8
|
+
tools: Anthropic.Tool[];
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const connections = new Map<string, MCPConnection>();
|
|
12
|
+
|
|
13
|
+
export async function connectMCPServer(
|
|
14
|
+
name: string,
|
|
15
|
+
command: string,
|
|
16
|
+
args: string[],
|
|
17
|
+
env?: Record<string, string>
|
|
18
|
+
): Promise<MCPConnection> {
|
|
19
|
+
if (connections.has(name)) return connections.get(name)!;
|
|
20
|
+
|
|
21
|
+
const transport = new StdioClientTransport({
|
|
22
|
+
command,
|
|
23
|
+
args,
|
|
24
|
+
env: { ...process.env, ...env } as Record<string, string>,
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
const client = new Client({ name: `tellet-${name}`, version: "1.0.0" });
|
|
28
|
+
await client.connect(transport);
|
|
29
|
+
|
|
30
|
+
const { tools: mcpTools } = await client.listTools();
|
|
31
|
+
|
|
32
|
+
const tools: Anthropic.Tool[] = mcpTools.map((t) => ({
|
|
33
|
+
name: `${name}__${t.name}`,
|
|
34
|
+
description: t.description || "",
|
|
35
|
+
input_schema: (t.inputSchema || { type: "object", properties: {} }) as Anthropic.Tool.InputSchema,
|
|
36
|
+
}));
|
|
37
|
+
|
|
38
|
+
const conn = { client, tools };
|
|
39
|
+
connections.set(name, conn);
|
|
40
|
+
return conn;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export async function callMCPTool(
|
|
44
|
+
qualifiedName: string,
|
|
45
|
+
input: Record<string, unknown>
|
|
46
|
+
): Promise<string> {
|
|
47
|
+
const [serverName, toolName] = qualifiedName.split("__", 2);
|
|
48
|
+
const conn = connections.get(serverName);
|
|
49
|
+
if (!conn) throw new Error(`MCP server "${serverName}" not connected`);
|
|
50
|
+
|
|
51
|
+
const result = await conn.client.callTool({ name: toolName, arguments: input });
|
|
52
|
+
return typeof result.content === "string"
|
|
53
|
+
? result.content
|
|
54
|
+
: JSON.stringify(result.content);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export async function getToolsForAgent(agentId: string): Promise<Anthropic.Tool[]> {
|
|
58
|
+
const config = getConfig();
|
|
59
|
+
const agentConfig = config.agents.find((a) => a.id === agentId);
|
|
60
|
+
if (!agentConfig) return [];
|
|
61
|
+
|
|
62
|
+
const tools: Anthropic.Tool[] = [];
|
|
63
|
+
const agentTools = (agentConfig as { tools?: string[] }).tools || [];
|
|
64
|
+
|
|
65
|
+
for (const toolId of agentTools) {
|
|
66
|
+
const toolConfig = (config as { tools?: Record<string, { type: string; package?: string; env?: Record<string, string>; description?: string }> }).tools?.[toolId];
|
|
67
|
+
if (!toolConfig) continue;
|
|
68
|
+
|
|
69
|
+
if (toolConfig.type === "builtin") {
|
|
70
|
+
// Built-in tools are handled separately (e.g., search_knowledge)
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (toolConfig.type === "mcp" && toolConfig.package) {
|
|
75
|
+
try {
|
|
76
|
+
const conn = await connectMCPServer(
|
|
77
|
+
toolId,
|
|
78
|
+
"npx",
|
|
79
|
+
["-y", toolConfig.package],
|
|
80
|
+
toolConfig.env
|
|
81
|
+
);
|
|
82
|
+
tools.push(...conn.tools);
|
|
83
|
+
} catch (err) {
|
|
84
|
+
console.error(`Failed to connect MCP server "${toolId}":`, err);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return tools;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export async function disconnectAll(): Promise<void> {
|
|
93
|
+
for (const [, conn] of connections) {
|
|
94
|
+
await conn.client.close();
|
|
95
|
+
}
|
|
96
|
+
connections.clear();
|
|
97
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import OpenAI from "openai";
|
|
2
|
+
import { createServerSupabase } from "@/lib/supabase";
|
|
3
|
+
|
|
4
|
+
let _openai: OpenAI | null = null;
|
|
5
|
+
function getOpenAI() {
|
|
6
|
+
if (!_openai) _openai = new OpenAI();
|
|
7
|
+
return _openai;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
async function embed(text: string): Promise<number[]> {
|
|
11
|
+
const res = await getOpenAI().embeddings.create({
|
|
12
|
+
model: "text-embedding-3-small",
|
|
13
|
+
input: text,
|
|
14
|
+
});
|
|
15
|
+
return res.data[0].embedding;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export async function searchKnowledge(query: string): Promise<string> {
|
|
19
|
+
try {
|
|
20
|
+
const embedding = await embed(query);
|
|
21
|
+
const supabase = await createServerSupabase();
|
|
22
|
+
|
|
23
|
+
const { data, error } = await supabase.rpc("match_documents", {
|
|
24
|
+
query_embedding: JSON.stringify(embedding),
|
|
25
|
+
match_count: 3,
|
|
26
|
+
match_threshold: 0.5,
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
if (error || !data || data.length === 0) {
|
|
30
|
+
return JSON.stringify({ results: [], message: "No matching documents found." });
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return JSON.stringify({
|
|
34
|
+
results: data.map((d: { title: string; content: string; similarity: number }) => ({
|
|
35
|
+
title: d.title,
|
|
36
|
+
content: d.content,
|
|
37
|
+
relevance: Math.round(d.similarity * 100) + "%",
|
|
38
|
+
})),
|
|
39
|
+
});
|
|
40
|
+
} catch {
|
|
41
|
+
return JSON.stringify({ results: [], message: "Knowledge base not configured yet." });
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export async function addDocument(
|
|
46
|
+
title: string,
|
|
47
|
+
content: string,
|
|
48
|
+
category?: string
|
|
49
|
+
): Promise<string> {
|
|
50
|
+
try {
|
|
51
|
+
const embedding = await embed(`${title}\n${content}`);
|
|
52
|
+
const supabase = await createServerSupabase();
|
|
53
|
+
|
|
54
|
+
const { error } = await supabase.from("documents").insert({
|
|
55
|
+
title,
|
|
56
|
+
content,
|
|
57
|
+
category: category || "general",
|
|
58
|
+
embedding: JSON.stringify(embedding),
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
if (error) return JSON.stringify({ error: error.message });
|
|
62
|
+
return JSON.stringify({ success: true, title });
|
|
63
|
+
} catch (err) {
|
|
64
|
+
return JSON.stringify({ error: err instanceof Error ? err.message : "Failed to add document" });
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export async function deleteDocument(documentId: string): Promise<string> {
|
|
69
|
+
const supabase = await createServerSupabase();
|
|
70
|
+
const { error } = await supabase.from("documents").delete().eq("id", documentId);
|
|
71
|
+
if (error) return JSON.stringify({ error: error.message });
|
|
72
|
+
return JSON.stringify({ success: true });
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export async function listDocuments(): Promise<string> {
|
|
76
|
+
const supabase = await createServerSupabase();
|
|
77
|
+
const { data, error } = await supabase
|
|
78
|
+
.from("documents")
|
|
79
|
+
.select("id, title, category, created_at")
|
|
80
|
+
.order("created_at", { ascending: false });
|
|
81
|
+
|
|
82
|
+
if (error) return JSON.stringify({ error: error.message });
|
|
83
|
+
return JSON.stringify({ documents: data || [] });
|
|
84
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool Registry — pre-defined MCP tools that can be added to tellet.
|
|
3
|
+
*
|
|
4
|
+
* Usage via Orchestrator: "Add Stripe to my agents"
|
|
5
|
+
* Usage via CLI: tool selection during setup
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export interface ToolRegistryEntry {
|
|
9
|
+
id: string;
|
|
10
|
+
name: string;
|
|
11
|
+
description: string;
|
|
12
|
+
package: string;
|
|
13
|
+
envKeys: { key: string; description: string; placeholder: string }[];
|
|
14
|
+
compatibleRoles: string[];
|
|
15
|
+
category: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const TOOL_REGISTRY: ToolRegistryEntry[] = [
|
|
19
|
+
{
|
|
20
|
+
id: "stripe",
|
|
21
|
+
name: "Stripe",
|
|
22
|
+
description: "Accept payments, create invoices, manage subscriptions",
|
|
23
|
+
package: "@stripe/mcp",
|
|
24
|
+
envKeys: [
|
|
25
|
+
{
|
|
26
|
+
key: "STRIPE_SECRET_KEY",
|
|
27
|
+
description: "Stripe secret key (use restricted key for safety)",
|
|
28
|
+
placeholder: "rk_live_...",
|
|
29
|
+
},
|
|
30
|
+
],
|
|
31
|
+
compatibleRoles: ["sales", "customer_support", "operations"],
|
|
32
|
+
category: "payments",
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
id: "email",
|
|
36
|
+
name: "Email (Resend)",
|
|
37
|
+
description: "Send emails, manage contacts, campaigns",
|
|
38
|
+
package: "resend-mcp",
|
|
39
|
+
envKeys: [
|
|
40
|
+
{
|
|
41
|
+
key: "RESEND_API_KEY",
|
|
42
|
+
description: "Resend API key",
|
|
43
|
+
placeholder: "re_...",
|
|
44
|
+
},
|
|
45
|
+
],
|
|
46
|
+
compatibleRoles: ["marketing", "customer_support", "sales"],
|
|
47
|
+
category: "communication",
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
id: "github",
|
|
51
|
+
name: "GitHub",
|
|
52
|
+
description: "Manage repos, issues, PRs",
|
|
53
|
+
package: "@modelcontextprotocol/server-github",
|
|
54
|
+
envKeys: [
|
|
55
|
+
{
|
|
56
|
+
key: "GITHUB_TOKEN",
|
|
57
|
+
description: "GitHub personal access token",
|
|
58
|
+
placeholder: "ghp_...",
|
|
59
|
+
},
|
|
60
|
+
],
|
|
61
|
+
compatibleRoles: ["development", "operations"],
|
|
62
|
+
category: "development",
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
id: "slack",
|
|
66
|
+
name: "Slack",
|
|
67
|
+
description: "Send messages, manage channels",
|
|
68
|
+
package: "@anthropic-ai/mcp-server-slack",
|
|
69
|
+
envKeys: [
|
|
70
|
+
{
|
|
71
|
+
key: "SLACK_BOT_TOKEN",
|
|
72
|
+
description: "Slack bot token",
|
|
73
|
+
placeholder: "xoxb-...",
|
|
74
|
+
},
|
|
75
|
+
],
|
|
76
|
+
compatibleRoles: ["customer_support", "marketing", "operations"],
|
|
77
|
+
category: "communication",
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
id: "notion",
|
|
81
|
+
name: "Notion",
|
|
82
|
+
description: "Manage pages, databases, documents",
|
|
83
|
+
package: "@anthropic-ai/mcp-server-notion",
|
|
84
|
+
envKeys: [
|
|
85
|
+
{
|
|
86
|
+
key: "NOTION_API_KEY",
|
|
87
|
+
description: "Notion integration token",
|
|
88
|
+
placeholder: "ntn_...",
|
|
89
|
+
},
|
|
90
|
+
],
|
|
91
|
+
compatibleRoles: ["operations", "marketing", "development"],
|
|
92
|
+
category: "productivity",
|
|
93
|
+
},
|
|
94
|
+
];
|
|
95
|
+
|
|
96
|
+
export function getToolById(id: string): ToolRegistryEntry | undefined {
|
|
97
|
+
return TOOL_REGISTRY.find((t) => t.id === id);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function getToolsByCategory(category: string): ToolRegistryEntry[] {
|
|
101
|
+
return TOOL_REGISTRY.filter((t) => t.category === category);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export function getToolsForRole(role: string): ToolRegistryEntry[] {
|
|
105
|
+
return TOOL_REGISTRY.filter((t) => t.compatibleRoles.includes(role));
|
|
106
|
+
}
|