Initial implementation of Telegram AI customer support bot

Cloudflare Workers + Hono + D1 + KV + R2 stack with 4 specialized AI agents
(onboarding, troubleshoot, asset, billing), OpenAI function calling with
7 tool definitions, human escalation, pending action approval workflow,
feedback collection, audit logging, i18n (ko/en), and Workers AI fallback.

43 source files, 45 tests passing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
kappa
2026-02-11 13:21:38 +09:00
commit 1d6b64c9e4
58 changed files with 12857 additions and 0 deletions

470
src/types.ts Normal file
View File

@@ -0,0 +1,470 @@
// ============================================
// Environment
// ============================================
export interface Env {
DB: D1Database;
AI: Ai;
BOT_TOKEN: string;
WEBHOOK_SECRET: string;
OPENAI_API_KEY?: string;
ADMIN_TELEGRAM_IDS?: string;
ENVIRONMENT?: string;
// Financial
DEPOSIT_BANK_NAME?: string;
DEPOSIT_BANK_ACCOUNT?: string;
DEPOSIT_BANK_HOLDER?: string;
// API URLs
OPENAI_API_BASE?: string;
D2_RENDER_URL?: string;
NAMECHEAP_API_URL?: string;
WHOIS_API_URL?: string;
CLOUD_ORCHESTRATOR_URL?: string;
CLOUD_ORCHESTRATOR?: Fetcher;
// KV Namespaces
RATE_LIMIT_KV: KVNamespace;
SESSION_KV: KVNamespace;
CACHE_KV: KVNamespace;
// R2
R2_BUCKET: R2Bucket;
}
// ============================================
// Telegram Types
// ============================================
export interface TelegramUpdate {
update_id: number;
message?: TelegramMessage;
callback_query?: CallbackQuery;
}
export interface CallbackQuery {
id: string;
from: TelegramUser;
message?: TelegramMessage;
chat_instance: string;
data?: string;
}
export interface TelegramMessage {
message_id: number;
from: TelegramUser;
chat: TelegramChat;
date: number;
text?: string;
}
export interface TelegramUser {
id: number;
is_bot: boolean;
first_name: string;
last_name?: string;
username?: string;
language_code?: string;
}
export interface TelegramChat {
id: number;
type: string;
}
// ============================================
// OpenAI Types (Function Calling)
// ============================================
export interface OpenAIToolCall {
id: string;
type: 'function';
function: {
name: string;
arguments: string;
};
}
export interface OpenAIMessage {
role: 'system' | 'user' | 'assistant' | 'tool';
content: string | null;
tool_calls?: OpenAIToolCall[];
tool_call_id?: string;
name?: string;
}
export interface OpenAIChoice {
message: OpenAIMessage;
finish_reason: string;
}
export interface OpenAIAPIResponse {
choices: OpenAIChoice[];
}
export interface ToolDefinition {
type: 'function';
function: {
name: string;
description: string;
parameters: {
type: 'object';
properties: Record<string, unknown>;
required?: string[];
};
};
}
// ============================================
// Workers AI Types (Fallback)
// ============================================
export type WorkersAIModel =
| "@cf/meta/llama-3.1-8b-instruct"
| "@cf/meta/llama-3.2-3b-instruct";
export interface WorkersAIMessage {
role: "system" | "user" | "assistant";
content: string;
}
// ============================================
// User & Auth Types
// ============================================
export type UserRole = 'admin' | 'user';
export interface User {
id: number;
telegram_id: string;
username: string | null;
first_name: string | null;
role: UserRole;
language_code: string;
context_limit: number;
last_active_at: string | null;
is_blocked: number;
blocked_reason: string | null;
created_at: string;
updated_at: string;
}
// ============================================
// Financial Types
// ============================================
export interface Wallet {
id: number;
user_id: number;
balance: number;
currency: string;
version: number;
created_at: string;
updated_at: string;
}
export type TransactionType = 'deposit' | 'withdrawal' | 'refund' | 'charge';
export type TransactionStatus = 'pending' | 'confirmed' | 'rejected' | 'cancelled';
export interface Transaction {
id: number;
user_id: number;
type: TransactionType;
amount: number;
status: TransactionStatus;
depositor_name: string | null;
depositor_name_prefix: string | null;
description: string | null;
reference_type: string | null;
reference_id: number | null;
confirmed_by: number | null;
confirmed_at: string | null;
created_at: string;
}
export interface BankNotification {
bankName: string;
depositorName: string;
amount: number;
balanceAfter?: number;
transactionTime?: Date;
rawMessage: string;
}
// ============================================
// Asset Types
// ============================================
export type DomainStatus = 'active' | 'expired' | 'pending' | 'suspended';
export interface Domain {
id: number;
user_id: number;
domain: string;
status: DomainStatus;
registrar: string | null;
nameservers: string | null;
auto_renew: number;
expiry_date: string | null;
created_at: string;
updated_at: string;
}
export type ServerStatus = 'pending' | 'provisioning' | 'running' | 'stopped' | 'terminated' | 'failed';
export interface Server {
id: number;
user_id: number;
provider: string;
instance_id: string | null;
label: string | null;
ip_address: string | null;
region: string | null;
spec_label: string | null;
monthly_price: number | null;
status: ServerStatus;
image: string | null;
provisioned_at: string | null;
terminated_at: string | null;
expires_at: string | null;
created_at: string;
updated_at: string;
}
export interface DdosService {
id: number;
user_id: number;
target: string;
protection_level: 'basic' | 'standard' | 'premium';
status: 'active' | 'inactive' | 'suspended';
provider: string | null;
monthly_price: number | null;
expiry_date: string | null;
}
export interface VpnService {
id: number;
user_id: number;
protocol: 'wireguard' | 'openvpn' | 'ipsec';
status: 'active' | 'inactive' | 'suspended';
endpoint: string | null;
monthly_price: number | null;
expiry_date: string | null;
}
// ============================================
// Support Types
// ============================================
export interface Feedback {
id: number;
user_id: number;
session_type: string;
rating: number;
comment: string | null;
created_at: string;
}
export type PendingActionStatus = 'pending' | 'approved' | 'rejected' | 'executed' | 'failed';
export interface PendingAction {
id: number;
user_id: number;
action_type: string;
target: string;
params: string;
status: PendingActionStatus;
approved_by: number | null;
created_at: string;
executed_at: string | null;
}
export interface AuditLog {
id: number;
actor_id: number | null;
action: string;
resource_type: string;
resource_id: string | null;
details: string | null;
result: 'success' | 'failure';
request_id: string | null;
created_at: string;
}
export interface KnowledgeArticle {
id: number;
category: string;
title: string;
content: string;
tags: string | null;
language: string;
is_active: number;
created_at: string;
updated_at: string;
}
// ============================================
// Agent Session Types
// ============================================
export type OnboardingSessionStatus = 'greeting' | 'gathering' | 'suggesting' | 'completed';
export interface OnboardingSession {
user_id: string;
status: OnboardingSessionStatus;
collected_info: {
purpose?: string;
requirements?: string;
budget?: string;
tech_stack?: string[];
};
messages: Array<{ role: 'user' | 'assistant'; content: string }>;
created_at: number;
updated_at: number;
expires_at: number;
}
export type TroubleshootSessionStatus = 'gathering' | 'diagnosing' | 'suggesting' | 'escalated' | 'completed';
export interface TroubleshootSession {
user_id: string;
status: TroubleshootSessionStatus;
collected_info: {
category?: string;
symptoms?: string;
environment?: string;
errorMessage?: string;
affected_service?: string;
};
messages: Array<{ role: 'user' | 'assistant'; content: string }>;
escalation_count: number;
created_at: number;
updated_at: number;
expires_at: number;
}
export type AssetSessionStatus = 'idle' | 'viewing' | 'managing' | 'completed';
export interface AssetSession {
user_id: string;
status: AssetSessionStatus;
collected_info: Record<string, unknown>;
messages: Array<{ role: 'user' | 'assistant'; content: string }>;
created_at: number;
updated_at: number;
expires_at: number;
}
export type BillingSessionStatus = 'collecting_amount' | 'collecting_name' | 'confirming' | 'completed';
export interface BillingSession {
user_id: string;
status: BillingSessionStatus;
collected_info: {
amount?: number;
depositor_name?: string;
};
messages: Array<{ role: 'user' | 'assistant'; content: string }>;
created_at: number;
updated_at: number;
expires_at: number;
}
// ============================================
// Tool Argument Types
// ============================================
export interface ManageDomainArgs {
action: 'check' | 'whois' | 'list' | 'info' | 'set_ns' | 'price';
domain?: string;
nameservers?: string[];
tld?: string;
}
export interface ManageWalletArgs {
action: 'balance' | 'account' | 'request' | 'history' | 'cancel';
depositor_name?: string;
amount?: number;
transaction_id?: number;
limit?: number;
}
export interface ManageServerArgs {
action: 'list' | 'info' | 'start' | 'stop' | 'reboot';
server_id?: number;
}
export interface CheckServiceArgs {
action: 'status' | 'list';
service_type?: 'ddos' | 'vpn' | 'all';
service_id?: number;
}
export interface RenderD2Args {
source: string;
format?: 'svg' | 'png';
}
export interface AdminArgs {
action: 'block_user' | 'unblock_user' | 'set_role' | 'broadcast' | 'confirm_deposit' | 'reject_deposit' | 'list_pending';
target_user_id?: string;
role?: UserRole;
message?: string;
transaction_id?: number;
reason?: string;
}
export interface ApproveActionArgs {
action_id: number;
approve: boolean;
reason?: string;
}
// ============================================
// Inline Keyboard Data
// ============================================
export interface FeedbackKeyboardData {
type: 'feedback';
session_type: string;
rating: number;
}
export interface ActionApprovalKeyboardData {
type: 'action_approval';
action_id: number;
approve: boolean;
}
export interface EscalationKeyboardData {
type: 'escalation';
session_id: string;
action: 'accept' | 'reject';
}
export type KeyboardCallbackData =
| FeedbackKeyboardData
| ActionApprovalKeyboardData
| EscalationKeyboardData;
// ============================================
// D2 Rendering
// ============================================
export interface D2RenderRequest {
source: string;
format: 'svg' | 'png';
}
export interface D2RenderResponse {
success: boolean;
image?: ArrayBuffer;
error?: string;
}
// ============================================
// Request Context
// ============================================
export interface RequestContext {
requestId: string;
userId?: string;
startTime: number;
}