@austinchen705/chatbot-intg-skill 1.0.1
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 +137 -0
- package/bin/cli.js +162 -0
- package/package.json +21 -0
- package/templates/SKILL.md +452 -0
- package/templates/resources/chatbot_integration_spec_v0.7.pdf +0 -0
- package/templates/resources/integration-playbook.md +625 -0
package/README.md
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# @austinchen705/chatbot-intg-skill
|
|
2
|
+
|
|
3
|
+
An AI skill installer for **Claude Code**, **Codex**, and **Gemini** that guides vendors through complete AI Chatbot API integration — covering auth, chat lifecycle, escalation handling, error resilience, analysis, and debugging.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
Run directly with `npx` (no install required):
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npx @austinchen705/chatbot-intg-skill
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Or install globally:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install -g @austinchen705/chatbot-intg-skill
|
|
17
|
+
chatbot-intg-skill
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Usage
|
|
21
|
+
|
|
22
|
+
### Interactive (default)
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npx @austinchen705/chatbot-intg-skill
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The installer will prompt you to select the target AI coding tool:
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
AI Chatbot Integration Skill Installer
|
|
32
|
+
=======================================
|
|
33
|
+
|
|
34
|
+
Install for which tools? (comma-separated)
|
|
35
|
+
1) claude 2) codex 3) gemini 4) all
|
|
36
|
+
>
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Non-interactive (CI / scripted)
|
|
40
|
+
|
|
41
|
+
Use the `--tool` flag to skip the prompt:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
# Single tool
|
|
45
|
+
npx @austinchen705/chatbot-intg-skill --tool claude
|
|
46
|
+
|
|
47
|
+
# Multiple tools
|
|
48
|
+
npx @austinchen705/chatbot-intg-skill --tool claude,codex
|
|
49
|
+
|
|
50
|
+
# All tools
|
|
51
|
+
npx @austinchen705/chatbot-intg-skill --tool all
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## What Gets Installed
|
|
55
|
+
|
|
56
|
+
| Tool | Skill files | Command / Instruction file |
|
|
57
|
+
|------|-------------|---------------------------|
|
|
58
|
+
| Claude Code | `.claude/skills/chatbot-intg/` | `.claude/commands/chatbot-intg.md` |
|
|
59
|
+
| Codex | `.codex/skills/chatbot-intg/` | `.codex/AGENTS.md` (manual step) |
|
|
60
|
+
| Gemini | `.gemini/skills/chatbot-intg/` | `.gemini/GEMINI.md` (manual step) |
|
|
61
|
+
|
|
62
|
+
### Installed files
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
SKILL.md # Phased integration workflow
|
|
66
|
+
resources/
|
|
67
|
+
chatbot_integration_spec.pdf # API spec reference (v0.7)
|
|
68
|
+
integration-playbook.md # Language-specific code templates
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Invoking the Skill
|
|
72
|
+
|
|
73
|
+
**Claude Code** — the command is auto-detected after install:
|
|
74
|
+
|
|
75
|
+
```
|
|
76
|
+
/chatbot-intg
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
**Codex** — add the following line to `.codex/AGENTS.md`:
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
Read .codex/skills/chatbot-intg/SKILL.md for vendor integration workflow
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
**Gemini** — add the following line to `.gemini/GEMINI.md`:
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
Read .gemini/skills/chatbot-intg/SKILL.md for vendor integration workflow
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Integration Workflow
|
|
92
|
+
|
|
93
|
+
The skill guides vendors through **6 gated phases**, each requiring user confirmation before proceeding:
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
Phase 0: Infrastructure Language + framework + logging setup
|
|
97
|
+
↓ (confirm)
|
|
98
|
+
Phase 1: Auth & Connectivity JWT token lifecycle + auto-refresh
|
|
99
|
+
↓ (confirm)
|
|
100
|
+
Phase 2: Core Chat Flow Session dispatch → send loop → kickout + escalation
|
|
101
|
+
↓ (confirm)
|
|
102
|
+
Phase 3: Error Handling Unified error framework + retry + circuit breaker
|
|
103
|
+
↓ (confirm)
|
|
104
|
+
Phase 4: Advanced (optional) Chat Analysis + MCP Server guide
|
|
105
|
+
↓ (confirm)
|
|
106
|
+
Phase 5: Acceptance Integration test checklist + debug handbook
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Supported Languages
|
|
110
|
+
|
|
111
|
+
- Python (FastAPI / Django · httpx / requests · tenacity)
|
|
112
|
+
- Java (Spring Boot · OkHttp / RestTemplate · Resilience4j)
|
|
113
|
+
- C# (ASP.NET Core · HttpClient · Polly)
|
|
114
|
+
- Node.js (Express / NestJS · axios · cockatiel)
|
|
115
|
+
|
|
116
|
+
### Covered APIs
|
|
117
|
+
|
|
118
|
+
| Method | Route | Description |
|
|
119
|
+
|--------|-------|-------------|
|
|
120
|
+
| POST | `/api/v1/auth` | Obtain JWT Token |
|
|
121
|
+
| POST | `/api/v1/chatbot/dispatch` | Create chat session |
|
|
122
|
+
| GET | `/api/v1/chatbot/usage` | Query quota |
|
|
123
|
+
| POST | `/api/v1/chatbot/kickout` | Close a session |
|
|
124
|
+
| POST | `/api/v1/chatbot/killall` | Close all sessions |
|
|
125
|
+
| POST | `/api/v1/chat/send` | Send message + receive AI response |
|
|
126
|
+
| GET | `/api/v1/chat/history/{sessionId}` | Retrieve chat history |
|
|
127
|
+
| POST | `/api/v1/analysis/create` | Submit conversation for analysis |
|
|
128
|
+
| GET | `/api/v1/analysis/{sessionId}` | Poll analysis result |
|
|
129
|
+
|
|
130
|
+
## Requirements
|
|
131
|
+
|
|
132
|
+
- Node.js >= 14
|
|
133
|
+
- Run from the **root of your project** so skill files land in the right directories
|
|
134
|
+
|
|
135
|
+
## License
|
|
136
|
+
|
|
137
|
+
MIT
|
package/bin/cli.js
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const readline = require('readline');
|
|
6
|
+
|
|
7
|
+
const TARGETS = {
|
|
8
|
+
claude: {
|
|
9
|
+
skillDir: '.claude/skills/chatbot-intg',
|
|
10
|
+
commandDir: '.claude/commands',
|
|
11
|
+
commandFile: 'chatbot-intg.md',
|
|
12
|
+
instructionFile: null,
|
|
13
|
+
postInstall: ' Claude Code: skill auto-detected. Use /chatbot-intg to invoke.',
|
|
14
|
+
},
|
|
15
|
+
codex: {
|
|
16
|
+
skillDir: '.codex/skills/chatbot-intg',
|
|
17
|
+
commandDir: null,
|
|
18
|
+
commandFile: null,
|
|
19
|
+
instructionFile: '.codex/AGENTS.md',
|
|
20
|
+
postInstall: ' Codex: add to .codex/AGENTS.md:\n' +
|
|
21
|
+
' "Read .codex/skills/chatbot-intg/SKILL.md for vendor integration workflow"',
|
|
22
|
+
},
|
|
23
|
+
gemini: {
|
|
24
|
+
skillDir: '.gemini/skills/chatbot-intg',
|
|
25
|
+
commandDir: null,
|
|
26
|
+
commandFile: null,
|
|
27
|
+
instructionFile: '.gemini/GEMINI.md',
|
|
28
|
+
postInstall: ' Gemini: add to .gemini/GEMINI.md:\n' +
|
|
29
|
+
' "Read .gemini/skills/chatbot-intg/SKILL.md for vendor integration workflow"',
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const COMMAND_TEMPLATE = `---
|
|
34
|
+
description: AI Chatbot Integration — guides vendors through complete API integration (auth, chat, escalation, error handling, analysis, debugging)
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
# Chatbot Integration Workflow
|
|
38
|
+
|
|
39
|
+
This command launches the chatbot-intg skill to guide a vendor through full AI Chatbot API integration.
|
|
40
|
+
|
|
41
|
+
## Startup
|
|
42
|
+
|
|
43
|
+
1. Read \`.claude/skills/chatbot-intg/SKILL.md\` and follow the phased workflow.
|
|
44
|
+
2. Read \`docs/chatbot_integration_spec.md\` as the authoritative API reference.
|
|
45
|
+
3. Reference \`.claude/skills/chatbot-intg/resources/integration-playbook.md\` for language-specific code templates.
|
|
46
|
+
|
|
47
|
+
## Execution
|
|
48
|
+
|
|
49
|
+
Begin with **Phase 0** — ask the vendor for their target language and integration scope, then proceed through each phase with user confirmation gates.
|
|
50
|
+
`;
|
|
51
|
+
|
|
52
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
53
|
+
|
|
54
|
+
function ask(question) {
|
|
55
|
+
return new Promise((resolve) => rl.question(question, resolve));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function copyDir(src, dest) {
|
|
59
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
60
|
+
for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
|
|
61
|
+
const srcPath = path.join(src, entry.name);
|
|
62
|
+
const destPath = path.join(dest, entry.name);
|
|
63
|
+
if (entry.isDirectory()) {
|
|
64
|
+
copyDir(srcPath, destPath);
|
|
65
|
+
} else {
|
|
66
|
+
fs.copyFileSync(srcPath, destPath);
|
|
67
|
+
console.log(` copied: ${destPath}`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function parseArgs() {
|
|
73
|
+
const args = process.argv.slice(2);
|
|
74
|
+
const toolFlag = args.indexOf('--tool');
|
|
75
|
+
if (toolFlag !== -1 && args[toolFlag + 1]) {
|
|
76
|
+
return args[toolFlag + 1].split(',').map((s) => s.trim().toLowerCase());
|
|
77
|
+
}
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async function selectTools() {
|
|
82
|
+
// Check --tool flag first
|
|
83
|
+
const fromArgs = parseArgs();
|
|
84
|
+
if (fromArgs) {
|
|
85
|
+
const valid = fromArgs.includes('all')
|
|
86
|
+
? Object.keys(TARGETS)
|
|
87
|
+
: fromArgs.filter((t) => TARGETS[t]);
|
|
88
|
+
if (valid.length > 0) return valid;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Interactive prompt
|
|
92
|
+
const answer = await ask(
|
|
93
|
+
' Install for which tools? (comma-separated)\n' +
|
|
94
|
+
' 1) claude 2) codex 3) gemini 4) all\n' +
|
|
95
|
+
' > '
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
if (answer.toLowerCase().includes('all') || answer.includes('4')) {
|
|
99
|
+
return Object.keys(TARGETS);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const mapping = { '1': 'claude', '2': 'codex', '3': 'gemini' };
|
|
103
|
+
return answer
|
|
104
|
+
.split(',')
|
|
105
|
+
.map((s) => {
|
|
106
|
+
const trimmed = s.trim().toLowerCase();
|
|
107
|
+
return mapping[trimmed] || trimmed;
|
|
108
|
+
})
|
|
109
|
+
.filter((s) => TARGETS[s]);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
async function main() {
|
|
113
|
+
console.log('');
|
|
114
|
+
console.log(' AI Chatbot Integration Skill Installer');
|
|
115
|
+
console.log(' =======================================');
|
|
116
|
+
console.log('');
|
|
117
|
+
|
|
118
|
+
const choices = await selectTools();
|
|
119
|
+
|
|
120
|
+
if (choices.length === 0) {
|
|
121
|
+
console.log(' No valid targets selected. Exiting.\n');
|
|
122
|
+
rl.close();
|
|
123
|
+
process.exit(1);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const templateDir = path.join(__dirname, '..', 'templates');
|
|
127
|
+
const cwd = process.cwd();
|
|
128
|
+
|
|
129
|
+
for (const tool of choices) {
|
|
130
|
+
const target = TARGETS[tool];
|
|
131
|
+
const dest = path.join(cwd, target.skillDir);
|
|
132
|
+
|
|
133
|
+
console.log(`\n [${tool}] Installing skill -> ${target.skillDir}/`);
|
|
134
|
+
copyDir(templateDir, dest);
|
|
135
|
+
|
|
136
|
+
// Create Claude Code command file
|
|
137
|
+
if (target.commandDir && target.commandFile) {
|
|
138
|
+
const cmdDir = path.join(cwd, target.commandDir);
|
|
139
|
+
const cmdFile = path.join(cmdDir, target.commandFile);
|
|
140
|
+
fs.mkdirSync(cmdDir, { recursive: true });
|
|
141
|
+
fs.writeFileSync(cmdFile, COMMAND_TEMPLATE);
|
|
142
|
+
console.log(` copied: ${cmdFile}`);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
console.log('\n =======================================');
|
|
147
|
+
console.log(' Installation complete!\n');
|
|
148
|
+
console.log(' Next steps:\n');
|
|
149
|
+
|
|
150
|
+
for (const tool of choices) {
|
|
151
|
+
console.log(TARGETS[tool].postInstall);
|
|
152
|
+
console.log('');
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
rl.close();
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
main().catch((err) => {
|
|
159
|
+
console.error(' Error:', err.message);
|
|
160
|
+
rl.close();
|
|
161
|
+
process.exit(1);
|
|
162
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@austinchen705/chatbot-intg-skill",
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "AI Chatbot integration skill for Claude Code / Codex / Gemini — guides vendors through complete API integration",
|
|
5
|
+
"bin": {
|
|
6
|
+
"chatbot-intg-skill": "./bin/cli.js"
|
|
7
|
+
},
|
|
8
|
+
"files": [
|
|
9
|
+
"bin/",
|
|
10
|
+
"templates/"
|
|
11
|
+
],
|
|
12
|
+
"keywords": [
|
|
13
|
+
"chatbot",
|
|
14
|
+
"integration",
|
|
15
|
+
"claude-code",
|
|
16
|
+
"codex",
|
|
17
|
+
"gemini",
|
|
18
|
+
"ai-skill"
|
|
19
|
+
],
|
|
20
|
+
"license": "MIT"
|
|
21
|
+
}
|
|
@@ -0,0 +1,452 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: chatbot-intg
|
|
3
|
+
description: AI Chatbot Integration Skill — guides vendors through complete Chatbot API integration including auth, chat, error handling, escalation, analysis, logging, and debugging. Supports Python / Java / C# / Node.js.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# AI Chatbot Integration Skill
|
|
7
|
+
|
|
8
|
+
Guides third-party vendors through complete AI Chatbot system integration. Based on `resources/chatbot_integration_spec.pdf`, this skill generates phased tasks, code templates, error handling frameworks, and debugging guides per target language.
|
|
9
|
+
|
|
10
|
+
## Use this skill when
|
|
11
|
+
|
|
12
|
+
- A vendor needs to integrate with the AI Chatbot API (auth, chat, analysis)
|
|
13
|
+
- Generating integration code for a specific language (Python / Java / C# / Node.js)
|
|
14
|
+
- Designing error handling and resilience patterns based on the spec
|
|
15
|
+
- Building debug/troubleshooting workflows and logging architecture
|
|
16
|
+
|
|
17
|
+
## Do not use this skill when
|
|
18
|
+
|
|
19
|
+
- Developing the Chatbot system internals (backend services, domain logic, database schema)
|
|
20
|
+
- Only looking up a single API spec or error code (use the Consult Agent directly)
|
|
21
|
+
- Building standalone applications unrelated to Chatbot API integration
|
|
22
|
+
|
|
23
|
+
## Knowledge Source
|
|
24
|
+
|
|
25
|
+
- **Integration Spec:** `resources/chatbot_integration_spec.pdf` (v0.7)
|
|
26
|
+
- **Implementation Templates:** `resources/integration-playbook.md`
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Workflow Overview
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
Phase 0: Infrastructure -> Language + Logging setup
|
|
34
|
+
| (user confirmation)
|
|
35
|
+
Phase 1: Auth & Connectivity -> Auth module + Token management
|
|
36
|
+
| (user confirmation)
|
|
37
|
+
Phase 2: Core Chat Flow -> Session + Chat + Escalation
|
|
38
|
+
| (user confirmation)
|
|
39
|
+
Phase 3: Error Handling -> Unified error framework + Resilience
|
|
40
|
+
| (user confirmation)
|
|
41
|
+
Phase 4: Advanced (optional) -> Chat Analysis + MCP Server guide
|
|
42
|
+
| (user confirmation)
|
|
43
|
+
Phase 5: Acceptance -> Test checklist + Debug handbook
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
**Each Phase requires user confirmation before proceeding to the next.**
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Phase 0: Infrastructure
|
|
51
|
+
|
|
52
|
+
### Goal
|
|
53
|
+
Confirm dev environment, tech stack, and establish the cross-cutting Logging approach.
|
|
54
|
+
|
|
55
|
+
### Steps
|
|
56
|
+
|
|
57
|
+
1. **Detect / Ask target language**
|
|
58
|
+
- Supported: Python / Java / C# / Node.js
|
|
59
|
+
- Confirm framework (e.g. Python: FastAPI/Django, Java: Spring Boot, C#: ASP.NET Core, Node.js: Express/NestJS)
|
|
60
|
+
- Confirm HTTP client preference (e.g. Python: httpx/requests, Java: OkHttp/RestTemplate)
|
|
61
|
+
|
|
62
|
+
2. **Confirm integration scope**
|
|
63
|
+
- AI Chatbot (required): Auth + Chat + Escalation
|
|
64
|
+
- Chat Analysis (optional): Post-conversation quality analysis
|
|
65
|
+
- MCP Server (optional): Custom tool extension
|
|
66
|
+
|
|
67
|
+
3. **Establish Logging approach**
|
|
68
|
+
- Ask the vendor about their existing logging setup and conventions
|
|
69
|
+
- Adapt all subsequent logging guidance to their architecture
|
|
70
|
+
- Ensure a **correlation ID** mechanism exists (or suggest adding one) to trace requests end-to-end
|
|
71
|
+
- All subsequent Phases will include logging points — these should follow the vendor's conventions
|
|
72
|
+
|
|
73
|
+
4. **Suggest project structure**
|
|
74
|
+
- Generate recommended directory layout per language
|
|
75
|
+
- Generate base HTTP client wrapper
|
|
76
|
+
|
|
77
|
+
### Output
|
|
78
|
+
- Language & framework confirmed
|
|
79
|
+
- Integration scope confirmed
|
|
80
|
+
- Logging approach agreed
|
|
81
|
+
- HTTP client base wrapper code
|
|
82
|
+
- Task list for subsequent Phases
|
|
83
|
+
|
|
84
|
+
### Gate
|
|
85
|
+
User confirms language, scope, and infrastructure before entering Phase 1.
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## Phase 1: Auth & Connectivity
|
|
90
|
+
|
|
91
|
+
### Goal
|
|
92
|
+
Implement JWT Token lifecycle management so all subsequent API calls carry a valid token.
|
|
93
|
+
|
|
94
|
+
### Knowledge Source
|
|
95
|
+
- Spec 2.1: Authentication
|
|
96
|
+
- Error codes: `AUTH_001`~`AUTH_004`, `TENANT_001`, `TENANT_003`
|
|
97
|
+
|
|
98
|
+
### Steps
|
|
99
|
+
|
|
100
|
+
1. **Implement AuthService / AuthClient**
|
|
101
|
+
- Wrap `POST /api/v1/auth`
|
|
102
|
+
- Secure API Key storage (env vars / secret manager — never hardcode)
|
|
103
|
+
- Define Request/Response DTOs
|
|
104
|
+
|
|
105
|
+
2. **Token caching & auto-refresh**
|
|
106
|
+
- In-memory cache with `expiresAt`
|
|
107
|
+
- Auto-detect expiry and refresh proactively (recommend 5 min before expiry)
|
|
108
|
+
- Thread-safe design (prevent concurrent refresh storms)
|
|
109
|
+
|
|
110
|
+
3. **Auth error handling**
|
|
111
|
+
- `AUTH_004` (invalid API Key) -> do NOT retry, escalate immediately
|
|
112
|
+
- `TENANT_003` (tenant inactive) -> do NOT retry, notify admin
|
|
113
|
+
- Network errors -> retry (max 3, exponential backoff)
|
|
114
|
+
|
|
115
|
+
4. **Logging**
|
|
116
|
+
- Log: auth success/failure, token refresh events, error codes
|
|
117
|
+
- NEVER log: raw API Key, full token (log only last 8 chars)
|
|
118
|
+
|
|
119
|
+
### Output
|
|
120
|
+
- AuthService complete code
|
|
121
|
+
- Token management module
|
|
122
|
+
- Auth-related error handling
|
|
123
|
+
- Unit test suggestions
|
|
124
|
+
|
|
125
|
+
### Gate
|
|
126
|
+
User confirms Auth module can successfully obtain a token before entering Phase 2.
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## Phase 2: Core Chat Flow
|
|
131
|
+
|
|
132
|
+
### Goal
|
|
133
|
+
Implement the full `dispatch -> send (loop) -> kickout` conversation lifecycle.
|
|
134
|
+
|
|
135
|
+
### Knowledge Source
|
|
136
|
+
- Spec 3.1: Flow Overview
|
|
137
|
+
- Spec 3.2.1~3.2.5: All Chatbot & Chat APIs
|
|
138
|
+
- Spec 6.4: EscalationReason enum
|
|
139
|
+
- Error codes: `CHATBOT_001`~`CHATBOT_009`, `CHAT_001`~`CHAT_019`
|
|
140
|
+
|
|
141
|
+
### Steps
|
|
142
|
+
|
|
143
|
+
1. **Session lifecycle management**
|
|
144
|
+
- `POST /api/v1/chatbot/dispatch` — create session
|
|
145
|
+
- Handle idempotency (same sessionId won't consume extra quota)
|
|
146
|
+
- Handle `timeZone` param (IANA format)
|
|
147
|
+
- `GET /api/v1/chatbot/usage` — check quota before dispatch
|
|
148
|
+
- `POST /api/v1/chatbot/kickout` — graceful close
|
|
149
|
+
- `POST /api/v1/chatbot/killall` — bulk close (admin use)
|
|
150
|
+
- **Cleanup on failure**: if unexpected error occurs after dispatch, ensure kickout is called (similar to finally/dispose pattern)
|
|
151
|
+
|
|
152
|
+
2. **Chat message send/receive**
|
|
153
|
+
- `POST /api/v1/chat/send`
|
|
154
|
+
- Required fields: `sessionId`, `message`, `userId`, `requestId`
|
|
155
|
+
- `requestId` for idempotency (recommend UUID)
|
|
156
|
+
- Client-side validation: message length <= 10,000 chars, sessionId 3~100 chars
|
|
157
|
+
- Response parsing: extract `content`, `escalationReason`, `shouldTransferHuman`
|
|
158
|
+
|
|
159
|
+
3. **Escalation handling**
|
|
160
|
+
- Detect `shouldTransferHuman: true`
|
|
161
|
+
- Handle by `escalationReason` (11 types):
|
|
162
|
+
|
|
163
|
+
| Code | Name | Recommended Action |
|
|
164
|
+
|------|------|-------------------|
|
|
165
|
+
| 1 | ConsecutiveUnableToAnswer | Transfer to agent + attach conversation summary |
|
|
166
|
+
| 2 | SpecialKeyword | Route to designated department |
|
|
167
|
+
| 3 | EmotionalAnomaly | Priority transfer + flag as high-sensitivity |
|
|
168
|
+
| 4 | DuplicateQuestion | Transfer to agent + flag as repeated |
|
|
169
|
+
| 5 | TurnLimitExceeded | Transfer to agent + inform user |
|
|
170
|
+
| 6 | HateSpeech | Escalate to supervisor + log incident |
|
|
171
|
+
| 7 | PersonalDataVerification | Route to identity verification flow |
|
|
172
|
+
| 8 | VendorKeyword | Handle per vendor-defined logic |
|
|
173
|
+
| 9 | AllAiProvidersInactive | Transfer to agent + inform AI unavailable |
|
|
174
|
+
| 10 | ToolsError | Transfer to agent + log tool failure |
|
|
175
|
+
| 11 | AiDeterminedEscalation | Transfer to agent |
|
|
176
|
+
|
|
177
|
+
- Generate EscalationHandler interface (vendor implements their own transfer logic)
|
|
178
|
+
|
|
179
|
+
4. **Chat history**
|
|
180
|
+
- `GET /api/v1/chat/history/{sessionId}` — retrieve conversation history
|
|
181
|
+
- Useful for attaching context when transferring to human agent
|
|
182
|
+
|
|
183
|
+
5. **Logging**
|
|
184
|
+
- Log each send: correlation ID, session ID, duration, status
|
|
185
|
+
- Log escalation events (including reason)
|
|
186
|
+
- Log session lifecycle (create/close/error)
|
|
187
|
+
|
|
188
|
+
### Output
|
|
189
|
+
- SessionManager module
|
|
190
|
+
- ChatService module
|
|
191
|
+
- EscalationHandler interface + default implementation
|
|
192
|
+
- All related DTOs
|
|
193
|
+
- Client-side validation logic
|
|
194
|
+
|
|
195
|
+
### Gate
|
|
196
|
+
User confirms full chat flow works correctly before entering Phase 3.
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## Phase 3: Error Handling & Resilience
|
|
201
|
+
|
|
202
|
+
### Goal
|
|
203
|
+
Build a unified error handling framework covering client validation, server business errors, and infrastructure errors.
|
|
204
|
+
|
|
205
|
+
### Knowledge Source
|
|
206
|
+
- Spec 2.2: Standard responses and error codes
|
|
207
|
+
- Spec 6.3: Complete error code reference (8 categories)
|
|
208
|
+
- Spec 2.2.3: Request timeout (60 seconds)
|
|
209
|
+
|
|
210
|
+
### Steps
|
|
211
|
+
|
|
212
|
+
1. **Unified API response parser**
|
|
213
|
+
- Standard structure: `{ isSuccess, data, error: { code, message, details, reference } }`
|
|
214
|
+
- Abstract `ApiResponse<T>` generic class
|
|
215
|
+
- All API calls go through this parser
|
|
216
|
+
|
|
217
|
+
2. **Three-layer error classification**
|
|
218
|
+
|
|
219
|
+
**Layer 1: Client-side Validation (pre-call interception)**
|
|
220
|
+
- sessionId length 3~100 (CHAT_014/015)
|
|
221
|
+
- message non-empty + length <= 10,000 (CHAT_003/013)
|
|
222
|
+
- requestId GUID format (CHAT_011)
|
|
223
|
+
- userId length <= 100 (CHAT_016)
|
|
224
|
+
- Basic XSS/SQLi pattern detection (INPUT_005/006)
|
|
225
|
+
|
|
226
|
+
**Layer 2: Server Business Error (API-returned business errors)**
|
|
227
|
+
- Classify handling strategy by error code prefix:
|
|
228
|
+
|
|
229
|
+
| Prefix | Category | Strategy |
|
|
230
|
+
|--------|----------|----------|
|
|
231
|
+
| AUTH_ | Auth error | Token refresh + retry / escalate |
|
|
232
|
+
| TENANT_ | Tenant error | No retry, notify admin |
|
|
233
|
+
| CHATBOT_ | Session error | Re-dispatch / escalate |
|
|
234
|
+
| CHAT_ | Chat error | Handle per specific code |
|
|
235
|
+
| INPUT_ | Validation error | Fix input + retry / report to user |
|
|
236
|
+
| ANALYSIS_ | Analysis error | Retry later / ignore |
|
|
237
|
+
| AI_PROVIDER_ | AI error | Fallback to human transfer |
|
|
238
|
+
| SYSTEM_ | System error | Retry + escalate |
|
|
239
|
+
|
|
240
|
+
**Layer 3: Infrastructure Error (network / timeout / unexpected exceptions)**
|
|
241
|
+
- HTTP timeout (60s) -> retry
|
|
242
|
+
- Connection refused -> retry + circuit breaker
|
|
243
|
+
- 5xx -> retry (max 3)
|
|
244
|
+
- Unexpected exceptions -> log + fallback response
|
|
245
|
+
|
|
246
|
+
3. **Retry & Resilience strategy**
|
|
247
|
+
- Retry: exponential backoff (1s -> 2s -> 4s), max 3 attempts
|
|
248
|
+
- Circuit breaker: 5 consecutive failures -> open for 30 seconds
|
|
249
|
+
- Timeout: 60 seconds per request
|
|
250
|
+
- Fallback: degraded response when all APIs are unavailable
|
|
251
|
+
- Generate language-specific implementation (Python: tenacity, Java: Resilience4j, C#: Polly, Node.js: cockatiel)
|
|
252
|
+
|
|
253
|
+
4. **Custom exception hierarchy**
|
|
254
|
+
- `ChatbotApiException` (base)
|
|
255
|
+
- `AuthenticationException`
|
|
256
|
+
- `SessionException`
|
|
257
|
+
- `ChatException`
|
|
258
|
+
- `ValidationException`
|
|
259
|
+
- Each exception carries `errorCode`, `message`, `details`
|
|
260
|
+
|
|
261
|
+
5. **Logging**
|
|
262
|
+
- Log every error: error code, HTTP status, retry count, correlation ID
|
|
263
|
+
- Log circuit breaker state changes
|
|
264
|
+
- Log retry events
|
|
265
|
+
|
|
266
|
+
### Output
|
|
267
|
+
- `ApiResponse<T>` unified parser module
|
|
268
|
+
- Client-side validator
|
|
269
|
+
- Error handler (three-layer classification logic)
|
|
270
|
+
- Retry / circuit breaker configuration
|
|
271
|
+
- Custom exception class hierarchy
|
|
272
|
+
- Error code lookup table (code -> handling strategy)
|
|
273
|
+
|
|
274
|
+
### Gate
|
|
275
|
+
User confirms error handling framework is complete before entering Phase 4.
|
|
276
|
+
|
|
277
|
+
---
|
|
278
|
+
|
|
279
|
+
## Phase 4: Advanced Features (Optional)
|
|
280
|
+
|
|
281
|
+
### Goal
|
|
282
|
+
Implement Chat Analysis integration and MCP Server development guide based on vendor needs.
|
|
283
|
+
|
|
284
|
+
### T9: Chat Analysis Integration
|
|
285
|
+
|
|
286
|
+
#### Knowledge Source
|
|
287
|
+
- Spec 4.1~4.2: Chat Analysis flow and APIs
|
|
288
|
+
|
|
289
|
+
#### Steps
|
|
290
|
+
|
|
291
|
+
1. **Submit analysis request**
|
|
292
|
+
- `POST /api/v1/analysis/create`
|
|
293
|
+
- Assemble `conversationMessages` (role: customer/cs/system)
|
|
294
|
+
- Assemble `categories` (id + description)
|
|
295
|
+
- Assemble `metadata` (userId, startTime, endTime, messageCount)
|
|
296
|
+
- Validation: at least 1 message, chronological order, timestamps cannot be in the future
|
|
297
|
+
|
|
298
|
+
2. **Poll analysis result**
|
|
299
|
+
- `GET /api/v1/analysis/{sessionId}`
|
|
300
|
+
- Handle statuses: `pending` -> `processing` -> `completed` / `failed`
|
|
301
|
+
- Polling strategy: initial 5s -> increment to 30s -> max polling duration 10 min
|
|
302
|
+
- 202 (processing) -> continue polling
|
|
303
|
+
- 200 (completed) -> parse `summary` (overview, resolution, categories)
|
|
304
|
+
|
|
305
|
+
3. **Error handling**
|
|
306
|
+
- `ANALYSIS_001` (not found) -> verify create was called
|
|
307
|
+
- `ANALYSIS_011` (in progress) -> wait for completion
|
|
308
|
+
- `ANALYSIS_009`/`ANALYSIS_010` -> fix input data
|
|
309
|
+
|
|
310
|
+
### T10: MCP Server Development Guide
|
|
311
|
+
|
|
312
|
+
#### Knowledge Source
|
|
313
|
+
- Spec 5.1~5.4: Complete MCP Server specification
|
|
314
|
+
|
|
315
|
+
#### Steps
|
|
316
|
+
|
|
317
|
+
1. **MCP Server architecture overview**
|
|
318
|
+
- Streamable HTTP transport
|
|
319
|
+
- Stateless design principle
|
|
320
|
+
- JWT authentication
|
|
321
|
+
|
|
322
|
+
2. **Tool definition conventions**
|
|
323
|
+
- snake_case naming, verb-first
|
|
324
|
+
- Description 50~200 chars, include use cases
|
|
325
|
+
- Structured return values (no plain text)
|
|
326
|
+
- Parameter Description is strongly recommended
|
|
327
|
+
|
|
328
|
+
3. **Example code**
|
|
329
|
+
- Generate MCP Server skeleton per vendor language
|
|
330
|
+
- C# reference: spec section 6.1
|
|
331
|
+
- Other languages: generate via MCP SDK
|
|
332
|
+
|
|
333
|
+
4. **Security configuration**
|
|
334
|
+
- JWT verification (HS256)
|
|
335
|
+
- Custom Headers support
|
|
336
|
+
- HTTPS enforcement
|
|
337
|
+
|
|
338
|
+
### Gate
|
|
339
|
+
User confirms advanced features are complete or skipped before entering Phase 5.
|
|
340
|
+
|
|
341
|
+
---
|
|
342
|
+
|
|
343
|
+
## Phase 5: Acceptance
|
|
344
|
+
|
|
345
|
+
### Goal
|
|
346
|
+
Generate integration test checklist and debug handbook so vendors can self-diagnose issues.
|
|
347
|
+
|
|
348
|
+
### T11: Integration Test Checklist
|
|
349
|
+
|
|
350
|
+
Generate test cases per API endpoint:
|
|
351
|
+
|
|
352
|
+
```
|
|
353
|
+
Auth
|
|
354
|
+
[ ] Valid API Key -> obtain token
|
|
355
|
+
[ ] Invalid API Key -> AUTH_004
|
|
356
|
+
[ ] Expired token -> auto-refresh succeeds
|
|
357
|
+
|
|
358
|
+
Session
|
|
359
|
+
[ ] dispatch -> obtain sessionId
|
|
360
|
+
[ ] Duplicate dispatch (same sessionId) -> no extra quota consumed
|
|
361
|
+
[ ] Quota full -> CHATBOT_001
|
|
362
|
+
[ ] kickout -> graceful close
|
|
363
|
+
[ ] kickout non-existent session -> CHATBOT_002
|
|
364
|
+
|
|
365
|
+
Chat
|
|
366
|
+
[ ] send message -> receive AI response
|
|
367
|
+
[ ] Empty message -> CHAT_003
|
|
368
|
+
[ ] Oversized message -> CHAT_013
|
|
369
|
+
[ ] send without dispatch -> CHAT_019
|
|
370
|
+
[ ] Escalation triggered -> shouldTransferHuman = true
|
|
371
|
+
|
|
372
|
+
Resilience
|
|
373
|
+
[ ] API timeout -> auto-retry
|
|
374
|
+
[ ] Mid-request token expiry -> auto-refresh + retry
|
|
375
|
+
[ ] Consecutive failures -> circuit breaker activates
|
|
376
|
+
|
|
377
|
+
Analysis (if enabled)
|
|
378
|
+
[ ] create -> 200 OK
|
|
379
|
+
[ ] Duplicate create -> 202 Accepted
|
|
380
|
+
[ ] get result (processing) -> continue polling
|
|
381
|
+
[ ] get result (completed) -> parse summary
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
### T12: Debug Handbook
|
|
385
|
+
|
|
386
|
+
1. **Error code quick reference**
|
|
387
|
+
- Generated from spec 6.3: error code -> cause -> troubleshooting steps -> solution
|
|
388
|
+
|
|
389
|
+
2. **Common issues FAQ**
|
|
390
|
+
- "Token keeps expiring" -> check clock sync / proactive refresh mechanism
|
|
391
|
+
- "dispatch always returns CHATBOT_001" -> check for un-closed sessions (kickout)
|
|
392
|
+
- "send returns CHAT_019" -> must dispatch first
|
|
393
|
+
- "AI keeps transferring to human" -> check escalationReason, may be GuardRail or emotion detection
|
|
394
|
+
|
|
395
|
+
3. **Log analysis guide**
|
|
396
|
+
- How to trace a full request chain using correlation ID
|
|
397
|
+
- How to distinguish client-side vs server-side issues
|
|
398
|
+
- How to locate retry / timeout / circuit breaker events from logs
|
|
399
|
+
|
|
400
|
+
4. **Self-service troubleshooting flowchart**
|
|
401
|
+
```
|
|
402
|
+
Issue occurs
|
|
403
|
+
-> Check errorCode
|
|
404
|
+
-> Look up in error code quick reference
|
|
405
|
+
-> Follow troubleshooting steps
|
|
406
|
+
-> Check related logs (filter by correlationId)
|
|
407
|
+
-> Determine which layer (client / server / network)
|
|
408
|
+
-> Apply corresponding solution
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
### Output
|
|
412
|
+
- Integration test checklist (exportable markdown)
|
|
413
|
+
- Debug handbook (error code reference, FAQ, log analysis guide)
|
|
414
|
+
- Self-service troubleshooting flowchart
|
|
415
|
+
|
|
416
|
+
### Gate
|
|
417
|
+
All phases complete.
|
|
418
|
+
|
|
419
|
+
---
|
|
420
|
+
|
|
421
|
+
## Completion Summary
|
|
422
|
+
|
|
423
|
+
After all Phases are complete, output final summary:
|
|
424
|
+
|
|
425
|
+
```
|
|
426
|
+
Chatbot Integration Complete
|
|
427
|
+
=============================
|
|
428
|
+
Language: [language]
|
|
429
|
+
Scope: [Chatbot / Analysis / MCP Server]
|
|
430
|
+
Modules:
|
|
431
|
+
- AuthService done
|
|
432
|
+
- SessionManager done
|
|
433
|
+
- ChatService done
|
|
434
|
+
- EscalationHandler done
|
|
435
|
+
- ErrorHandler done
|
|
436
|
+
- Retry/Resilience done
|
|
437
|
+
- Logger done
|
|
438
|
+
- Analysis (optional) done / skipped
|
|
439
|
+
- MCP Server (optional)done / skipped
|
|
440
|
+
|
|
441
|
+
Deliverables:
|
|
442
|
+
- Integration Test Checklist
|
|
443
|
+
- Debug Handbook
|
|
444
|
+
- Error Code Quick Reference
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
---
|
|
448
|
+
|
|
449
|
+
## Resources
|
|
450
|
+
|
|
451
|
+
- `resources/integration-playbook.md` — Language-specific implementation templates and code samples
|
|
452
|
+
- `resources/chatbot_integration_spec.pdf` — API integration spec (v0.7)
|
|
Binary file
|
|
@@ -0,0 +1,625 @@
|
|
|
1
|
+
# Integration Playbook
|
|
2
|
+
|
|
3
|
+
Language-specific implementation templates for AI Chatbot API integration.
|
|
4
|
+
|
|
5
|
+
> **Usage:** This playbook is referenced by `SKILL.md`. During each Phase, generate code based on the vendor's confirmed language and framework. The templates below provide structural patterns — adapt naming, style, and conventions to match the vendor's codebase.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 1. HTTP Client Base Wrapper
|
|
10
|
+
|
|
11
|
+
All API calls should go through a centralized HTTP client that handles:
|
|
12
|
+
- Base URL configuration
|
|
13
|
+
- Authorization header injection
|
|
14
|
+
- Standard response parsing
|
|
15
|
+
- Correlation ID propagation
|
|
16
|
+
- Timeout enforcement (60s default)
|
|
17
|
+
|
|
18
|
+
### Python (httpx)
|
|
19
|
+
|
|
20
|
+
```python
|
|
21
|
+
import httpx
|
|
22
|
+
import uuid
|
|
23
|
+
from dataclasses import dataclass
|
|
24
|
+
from typing import TypeVar, Generic, Optional
|
|
25
|
+
|
|
26
|
+
T = TypeVar("T")
|
|
27
|
+
|
|
28
|
+
@dataclass
|
|
29
|
+
class ApiError:
|
|
30
|
+
code: str
|
|
31
|
+
message: str
|
|
32
|
+
details: Optional[str] = None
|
|
33
|
+
reference: Optional[str] = None
|
|
34
|
+
|
|
35
|
+
@dataclass
|
|
36
|
+
class ApiResponse(Generic[T]):
|
|
37
|
+
is_success: bool
|
|
38
|
+
data: Optional[T] = None
|
|
39
|
+
error: Optional[ApiError] = None
|
|
40
|
+
|
|
41
|
+
class ChatbotHttpClient:
|
|
42
|
+
def __init__(self, base_url: str, auth_service):
|
|
43
|
+
self._base_url = base_url.rstrip("/")
|
|
44
|
+
self._auth = auth_service
|
|
45
|
+
self._client = httpx.AsyncClient(timeout=60.0)
|
|
46
|
+
|
|
47
|
+
async def request(self, method: str, path: str, **kwargs) -> dict:
|
|
48
|
+
token = await self._auth.get_token()
|
|
49
|
+
headers = {
|
|
50
|
+
"Authorization": f"Bearer {token}",
|
|
51
|
+
"X-Correlation-Id": str(uuid.uuid4()),
|
|
52
|
+
**kwargs.pop("headers", {}),
|
|
53
|
+
}
|
|
54
|
+
response = await self._client.request(
|
|
55
|
+
method, f"{self._base_url}{path}", headers=headers, **kwargs
|
|
56
|
+
)
|
|
57
|
+
response.raise_for_status()
|
|
58
|
+
return response.json()
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Java (OkHttp)
|
|
62
|
+
|
|
63
|
+
```java
|
|
64
|
+
public class ChatbotHttpClient {
|
|
65
|
+
private final String baseUrl;
|
|
66
|
+
private final AuthService authService;
|
|
67
|
+
private final OkHttpClient client;
|
|
68
|
+
|
|
69
|
+
public ChatbotHttpClient(String baseUrl, AuthService authService) {
|
|
70
|
+
this.baseUrl = baseUrl;
|
|
71
|
+
this.authService = authService;
|
|
72
|
+
this.client = new OkHttpClient.Builder()
|
|
73
|
+
.connectTimeout(60, TimeUnit.SECONDS)
|
|
74
|
+
.readTimeout(60, TimeUnit.SECONDS)
|
|
75
|
+
.build();
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
public <T> ApiResponse<T> request(String method, String path, Object body, Class<T> responseType) throws IOException {
|
|
79
|
+
String token = authService.getToken();
|
|
80
|
+
String correlationId = UUID.randomUUID().toString();
|
|
81
|
+
|
|
82
|
+
Request.Builder builder = new Request.Builder()
|
|
83
|
+
.url(baseUrl + path)
|
|
84
|
+
.header("Authorization", "Bearer " + token)
|
|
85
|
+
.header("X-Correlation-Id", correlationId);
|
|
86
|
+
|
|
87
|
+
// ... build request body, execute, parse response
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### C# (HttpClient)
|
|
93
|
+
|
|
94
|
+
```csharp
|
|
95
|
+
public class ChatbotHttpClient
|
|
96
|
+
{
|
|
97
|
+
private readonly HttpClient _httpClient;
|
|
98
|
+
private readonly IAuthService _authService;
|
|
99
|
+
|
|
100
|
+
public ChatbotHttpClient(HttpClient httpClient, IAuthService authService)
|
|
101
|
+
{
|
|
102
|
+
_httpClient = httpClient;
|
|
103
|
+
_authService = authService;
|
|
104
|
+
_httpClient.Timeout = TimeSpan.FromSeconds(60);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
public async Task<ApiResponse<T>> RequestAsync<T>(HttpMethod method, string path, object? body = null)
|
|
108
|
+
{
|
|
109
|
+
var token = await _authService.GetTokenAsync();
|
|
110
|
+
var correlationId = Guid.NewGuid().ToString();
|
|
111
|
+
|
|
112
|
+
var request = new HttpRequestMessage(method, path);
|
|
113
|
+
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
|
|
114
|
+
request.Headers.Add("X-Correlation-Id", correlationId);
|
|
115
|
+
|
|
116
|
+
if (body != null)
|
|
117
|
+
request.Content = JsonContent.Create(body);
|
|
118
|
+
|
|
119
|
+
var response = await _httpClient.SendAsync(request);
|
|
120
|
+
var content = await response.Content.ReadFromJsonAsync<ApiResponse<T>>();
|
|
121
|
+
return content!;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Node.js (axios)
|
|
127
|
+
|
|
128
|
+
```typescript
|
|
129
|
+
import axios, { AxiosInstance } from 'axios';
|
|
130
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
131
|
+
|
|
132
|
+
interface ApiResponse<T> {
|
|
133
|
+
isSuccess: boolean;
|
|
134
|
+
data: T | null;
|
|
135
|
+
error: { code: string; message: string; details?: string; reference?: string } | null;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
class ChatbotHttpClient {
|
|
139
|
+
private client: AxiosInstance;
|
|
140
|
+
private authService: AuthService;
|
|
141
|
+
|
|
142
|
+
constructor(baseUrl: string, authService: AuthService) {
|
|
143
|
+
this.authService = authService;
|
|
144
|
+
this.client = axios.create({
|
|
145
|
+
baseURL: baseUrl,
|
|
146
|
+
timeout: 60000,
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
async request<T>(method: string, path: string, data?: any): Promise<ApiResponse<T>> {
|
|
151
|
+
const token = await this.authService.getToken();
|
|
152
|
+
const response = await this.client.request<ApiResponse<T>>({
|
|
153
|
+
method,
|
|
154
|
+
url: path,
|
|
155
|
+
data,
|
|
156
|
+
headers: {
|
|
157
|
+
Authorization: `Bearer ${token}`,
|
|
158
|
+
'X-Correlation-Id': uuidv4(),
|
|
159
|
+
},
|
|
160
|
+
});
|
|
161
|
+
return response.data;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## 2. AuthService — Token Lifecycle
|
|
169
|
+
|
|
170
|
+
Key behaviors:
|
|
171
|
+
- Obtain token via `POST /api/v1/auth`
|
|
172
|
+
- Cache token in memory with `expiresAt`
|
|
173
|
+
- Auto-refresh 5 minutes before expiry
|
|
174
|
+
- Thread-safe (prevent concurrent refresh)
|
|
175
|
+
|
|
176
|
+
### Python
|
|
177
|
+
|
|
178
|
+
```python
|
|
179
|
+
import asyncio
|
|
180
|
+
from datetime import datetime, timezone, timedelta
|
|
181
|
+
|
|
182
|
+
class AuthService:
|
|
183
|
+
def __init__(self, base_url: str, api_key: str):
|
|
184
|
+
self._base_url = base_url
|
|
185
|
+
self._api_key = api_key
|
|
186
|
+
self._token: Optional[str] = None
|
|
187
|
+
self._expires_at: Optional[datetime] = None
|
|
188
|
+
self._lock = asyncio.Lock()
|
|
189
|
+
|
|
190
|
+
async def get_token(self) -> str:
|
|
191
|
+
if self._is_token_valid():
|
|
192
|
+
return self._token
|
|
193
|
+
|
|
194
|
+
async with self._lock:
|
|
195
|
+
# Double-check after acquiring lock
|
|
196
|
+
if self._is_token_valid():
|
|
197
|
+
return self._token
|
|
198
|
+
await self._refresh_token()
|
|
199
|
+
return self._token
|
|
200
|
+
|
|
201
|
+
def _is_token_valid(self) -> bool:
|
|
202
|
+
if not self._token or not self._expires_at:
|
|
203
|
+
return False
|
|
204
|
+
# Refresh 5 minutes before expiry
|
|
205
|
+
return datetime.now(timezone.utc) < self._expires_at - timedelta(minutes=5)
|
|
206
|
+
|
|
207
|
+
async def _refresh_token(self):
|
|
208
|
+
async with httpx.AsyncClient() as client:
|
|
209
|
+
response = await client.post(
|
|
210
|
+
f"{self._base_url}/api/v1/auth",
|
|
211
|
+
json={"apiKey": self._api_key},
|
|
212
|
+
)
|
|
213
|
+
response.raise_for_status()
|
|
214
|
+
data = response.json()["data"]
|
|
215
|
+
self._token = data["token"]
|
|
216
|
+
self._expires_at = datetime.fromisoformat(data["expiresAt"])
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
### C#
|
|
220
|
+
|
|
221
|
+
```csharp
|
|
222
|
+
public class AuthService : IAuthService
|
|
223
|
+
{
|
|
224
|
+
private readonly string _baseUrl;
|
|
225
|
+
private readonly string _apiKey;
|
|
226
|
+
private readonly HttpClient _httpClient;
|
|
227
|
+
private readonly SemaphoreSlim _lock = new(1, 1);
|
|
228
|
+
private string? _token;
|
|
229
|
+
private DateTimeOffset? _expiresAt;
|
|
230
|
+
|
|
231
|
+
public async Task<string> GetTokenAsync()
|
|
232
|
+
{
|
|
233
|
+
if (IsTokenValid()) return _token!;
|
|
234
|
+
|
|
235
|
+
await _lock.WaitAsync();
|
|
236
|
+
try
|
|
237
|
+
{
|
|
238
|
+
if (IsTokenValid()) return _token!;
|
|
239
|
+
await RefreshTokenAsync();
|
|
240
|
+
return _token!;
|
|
241
|
+
}
|
|
242
|
+
finally { _lock.Release(); }
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
private bool IsTokenValid()
|
|
246
|
+
=> _token != null && _expiresAt > DateTimeOffset.UtcNow.AddMinutes(5);
|
|
247
|
+
|
|
248
|
+
private async Task RefreshTokenAsync()
|
|
249
|
+
{
|
|
250
|
+
var response = await _httpClient.PostAsJsonAsync(
|
|
251
|
+
$"{_baseUrl}/api/v1/auth", new { apiKey = _apiKey });
|
|
252
|
+
response.EnsureSuccessStatusCode();
|
|
253
|
+
var result = await response.Content.ReadFromJsonAsync<ApiResponse<AuthData>>();
|
|
254
|
+
_token = result!.Data!.Token;
|
|
255
|
+
_expiresAt = result.Data.ExpiresAt;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
---
|
|
261
|
+
|
|
262
|
+
## 3. SessionManager
|
|
263
|
+
|
|
264
|
+
Key behaviors:
|
|
265
|
+
- `dispatch` -> create session (idempotent)
|
|
266
|
+
- Check quota via `usage` before dispatching
|
|
267
|
+
- `kickout` -> graceful close
|
|
268
|
+
- Cleanup guarantee (dispose/finally pattern)
|
|
269
|
+
|
|
270
|
+
### Pattern (language-agnostic pseudocode)
|
|
271
|
+
|
|
272
|
+
```
|
|
273
|
+
class SessionManager:
|
|
274
|
+
async dispatch(sessionId, timeZone?):
|
|
275
|
+
// 1. Check quota
|
|
276
|
+
usage = await client.GET("/api/v1/chatbot/usage")
|
|
277
|
+
if usage.isLimitReached:
|
|
278
|
+
throw QuotaExceededException
|
|
279
|
+
|
|
280
|
+
// 2. Dispatch
|
|
281
|
+
result = await client.POST("/api/v1/chatbot/dispatch", {sessionId, timeZone})
|
|
282
|
+
log("Session dispatched", {sessionId, remainingQuota: result.remainingQuota})
|
|
283
|
+
return result
|
|
284
|
+
|
|
285
|
+
async close(sessionId, reason?):
|
|
286
|
+
result = await client.POST("/api/v1/chatbot/kickout", {sessionId, reason})
|
|
287
|
+
log("Session closed", {sessionId})
|
|
288
|
+
return result
|
|
289
|
+
|
|
290
|
+
// Dispose pattern — ensure session is closed on error
|
|
291
|
+
async withSession(sessionId, callback):
|
|
292
|
+
try:
|
|
293
|
+
session = await dispatch(sessionId)
|
|
294
|
+
return await callback(session)
|
|
295
|
+
finally:
|
|
296
|
+
await close(sessionId, "auto-cleanup")
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
---
|
|
300
|
+
|
|
301
|
+
## 4. ChatService
|
|
302
|
+
|
|
303
|
+
Key behaviors:
|
|
304
|
+
- Send message and parse response
|
|
305
|
+
- Detect escalation signals
|
|
306
|
+
- Client-side validation before sending
|
|
307
|
+
|
|
308
|
+
### Pattern
|
|
309
|
+
|
|
310
|
+
```
|
|
311
|
+
class ChatService:
|
|
312
|
+
async send(sessionId, message, userId, requestId?):
|
|
313
|
+
// 1. Client-side validation
|
|
314
|
+
validate(sessionId, message, userId)
|
|
315
|
+
|
|
316
|
+
// 2. Send
|
|
317
|
+
requestId = requestId ?? generateUUID()
|
|
318
|
+
result = await client.POST("/api/v1/chat/send", {
|
|
319
|
+
sessionId, message, userId, requestId
|
|
320
|
+
})
|
|
321
|
+
|
|
322
|
+
// 3. Check escalation
|
|
323
|
+
if result.shouldTransferHuman:
|
|
324
|
+
await escalationHandler.handle(sessionId, result.escalationReason, result.content)
|
|
325
|
+
|
|
326
|
+
return result
|
|
327
|
+
|
|
328
|
+
validate(sessionId, message, userId):
|
|
329
|
+
if len(sessionId) < 3 or len(sessionId) > 100:
|
|
330
|
+
throw ValidationException("CHAT_014/015", "sessionId length must be 3-100")
|
|
331
|
+
if not message or len(message) > 10000:
|
|
332
|
+
throw ValidationException("CHAT_003/013", "message required, max 10000 chars")
|
|
333
|
+
if len(userId) > 100:
|
|
334
|
+
throw ValidationException("CHAT_016", "userId max 100 chars")
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
---
|
|
338
|
+
|
|
339
|
+
## 5. EscalationHandler
|
|
340
|
+
|
|
341
|
+
Interface pattern — vendor implements their own transfer logic.
|
|
342
|
+
|
|
343
|
+
### C# Example
|
|
344
|
+
|
|
345
|
+
```csharp
|
|
346
|
+
public interface IEscalationHandler
|
|
347
|
+
{
|
|
348
|
+
Task HandleAsync(string sessionId, int escalationReason, string aiMessage);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
public class DefaultEscalationHandler : IEscalationHandler
|
|
352
|
+
{
|
|
353
|
+
public async Task HandleAsync(string sessionId, int escalationReason, string aiMessage)
|
|
354
|
+
{
|
|
355
|
+
// Fetch conversation history for context
|
|
356
|
+
var history = await _chatClient.GetHistoryAsync(sessionId);
|
|
357
|
+
|
|
358
|
+
switch (escalationReason)
|
|
359
|
+
{
|
|
360
|
+
case 3: // EmotionalAnomaly
|
|
361
|
+
await TransferWithPriority(sessionId, history, priority: "high");
|
|
362
|
+
break;
|
|
363
|
+
case 6: // HateSpeech
|
|
364
|
+
await EscalateToSupervisor(sessionId, history);
|
|
365
|
+
break;
|
|
366
|
+
case 7: // PersonalDataVerification
|
|
367
|
+
await RouteToVerificationFlow(sessionId, history);
|
|
368
|
+
break;
|
|
369
|
+
default:
|
|
370
|
+
await TransferToAgent(sessionId, history);
|
|
371
|
+
break;
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
---
|
|
378
|
+
|
|
379
|
+
## 6. Error Handling Framework
|
|
380
|
+
|
|
381
|
+
### ApiResponse<T> — Unified Response Parser
|
|
382
|
+
|
|
383
|
+
```
|
|
384
|
+
class ApiResponse<T>:
|
|
385
|
+
isSuccess: bool
|
|
386
|
+
data: T?
|
|
387
|
+
error: ApiError?
|
|
388
|
+
|
|
389
|
+
class ApiError:
|
|
390
|
+
code: string // e.g. "AUTH_004"
|
|
391
|
+
message: string
|
|
392
|
+
details: string?
|
|
393
|
+
reference: string?
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
### Exception Hierarchy
|
|
397
|
+
|
|
398
|
+
```
|
|
399
|
+
ChatbotApiException (base)
|
|
400
|
+
|-- AuthenticationException (AUTH_*)
|
|
401
|
+
|-- TenantException (TENANT_*)
|
|
402
|
+
|-- SessionException (CHATBOT_*)
|
|
403
|
+
|-- ChatException (CHAT_*)
|
|
404
|
+
|-- ValidationException (INPUT_*, VALIDATION_*)
|
|
405
|
+
|-- AnalysisException (ANALYSIS_*)
|
|
406
|
+
|-- AiProviderException (AI_PROVIDER_*)
|
|
407
|
+
|-- SystemException (SYSTEM_*)
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
### Error Code -> Strategy Mapping
|
|
411
|
+
|
|
412
|
+
```
|
|
413
|
+
ERROR_CODE_STRATEGIES = {
|
|
414
|
+
# Auth — no retry (except network), escalate
|
|
415
|
+
"AUTH_001": {"retry": false, "action": "escalate"},
|
|
416
|
+
"AUTH_002": {"retry": false, "action": "re-authenticate"},
|
|
417
|
+
"AUTH_003": {"retry": true, "action": "retry_then_escalate"},
|
|
418
|
+
"AUTH_004": {"retry": false, "action": "escalate_invalid_key"},
|
|
419
|
+
|
|
420
|
+
# Tenant — no retry, admin notification
|
|
421
|
+
"TENANT_001": {"retry": false, "action": "notify_admin"},
|
|
422
|
+
"TENANT_003": {"retry": false, "action": "notify_admin"},
|
|
423
|
+
|
|
424
|
+
# Session — conditional retry
|
|
425
|
+
"CHATBOT_001": {"retry": false, "action": "check_quota_then_cleanup"},
|
|
426
|
+
"CHATBOT_002": {"retry": false, "action": "re_dispatch"},
|
|
427
|
+
"CHATBOT_003": {"retry": false, "action": "re_dispatch"},
|
|
428
|
+
|
|
429
|
+
# Chat — per-code handling
|
|
430
|
+
"CHAT_003": {"retry": false, "action": "fix_input"},
|
|
431
|
+
"CHAT_013": {"retry": false, "action": "truncate_message"},
|
|
432
|
+
"CHAT_019": {"retry": false, "action": "dispatch_first"},
|
|
433
|
+
|
|
434
|
+
# Input — fix and retry
|
|
435
|
+
"INPUT_005": {"retry": false, "action": "sanitize_input"},
|
|
436
|
+
"INPUT_006": {"retry": false, "action": "sanitize_input"},
|
|
437
|
+
|
|
438
|
+
# System — retry with backoff
|
|
439
|
+
"SYSTEM_001": {"retry": true, "action": "retry_then_escalate"},
|
|
440
|
+
}
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
---
|
|
444
|
+
|
|
445
|
+
## 7. Retry & Resilience
|
|
446
|
+
|
|
447
|
+
### Python (tenacity)
|
|
448
|
+
|
|
449
|
+
```python
|
|
450
|
+
from tenacity import retry, stop_after_attempt, wait_exponential, retry_if_exception_type
|
|
451
|
+
|
|
452
|
+
@retry(
|
|
453
|
+
stop=stop_after_attempt(3),
|
|
454
|
+
wait=wait_exponential(multiplier=1, min=1, max=4),
|
|
455
|
+
retry=retry_if_exception_type((httpx.TimeoutException, httpx.NetworkError)),
|
|
456
|
+
)
|
|
457
|
+
async def call_with_retry(func, *args, **kwargs):
|
|
458
|
+
return await func(*args, **kwargs)
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
### C# (Polly)
|
|
462
|
+
|
|
463
|
+
```csharp
|
|
464
|
+
var retryPolicy = Policy
|
|
465
|
+
.Handle<HttpRequestException>()
|
|
466
|
+
.Or<TaskCanceledException>()
|
|
467
|
+
.WaitAndRetryAsync(3, attempt => TimeSpan.FromSeconds(Math.Pow(2, attempt - 1)));
|
|
468
|
+
|
|
469
|
+
var circuitBreaker = Policy
|
|
470
|
+
.Handle<HttpRequestException>()
|
|
471
|
+
.CircuitBreakerAsync(5, TimeSpan.FromSeconds(30));
|
|
472
|
+
|
|
473
|
+
var resilience = Policy.WrapAsync(retryPolicy, circuitBreaker);
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
### Java (Resilience4j)
|
|
477
|
+
|
|
478
|
+
```java
|
|
479
|
+
RetryConfig retryConfig = RetryConfig.custom()
|
|
480
|
+
.maxAttempts(3)
|
|
481
|
+
.waitDuration(Duration.ofSeconds(1))
|
|
482
|
+
.retryExceptions(IOException.class, TimeoutException.class)
|
|
483
|
+
.build();
|
|
484
|
+
|
|
485
|
+
CircuitBreakerConfig cbConfig = CircuitBreakerConfig.custom()
|
|
486
|
+
.failureRateThreshold(50)
|
|
487
|
+
.waitDurationInOpenState(Duration.ofSeconds(30))
|
|
488
|
+
.slidingWindowSize(5)
|
|
489
|
+
.build();
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
### Node.js (cockatiel)
|
|
493
|
+
|
|
494
|
+
```typescript
|
|
495
|
+
import { retry, handleAll, ExponentialBackoff, circuitBreaker, SamplingBreaker, wrap } from 'cockatiel';
|
|
496
|
+
|
|
497
|
+
const retryPolicy = retry(handleAll, { maxAttempts: 3, backoff: new ExponentialBackoff() });
|
|
498
|
+
const breaker = circuitBreaker(handleAll, {
|
|
499
|
+
halfOpenAfter: 30 * 1000,
|
|
500
|
+
breaker: new SamplingBreaker({ threshold: 0.5, duration: 30 * 1000, minimumRps: 1 }),
|
|
501
|
+
});
|
|
502
|
+
const resilience = wrap(retryPolicy, breaker);
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
---
|
|
506
|
+
|
|
507
|
+
## 8. Chat Analysis (Optional)
|
|
508
|
+
|
|
509
|
+
### Polling Pattern
|
|
510
|
+
|
|
511
|
+
```
|
|
512
|
+
class AnalysisService:
|
|
513
|
+
async createAnalysis(sessionId, messages, categories?, metadata?):
|
|
514
|
+
return await client.POST("/api/v1/analysis/create", {
|
|
515
|
+
sessionId, conversationMessages: messages, categories, metadata
|
|
516
|
+
})
|
|
517
|
+
|
|
518
|
+
async waitForResult(sessionId, maxWaitSeconds=600):
|
|
519
|
+
interval = 5 // start at 5 seconds
|
|
520
|
+
elapsed = 0
|
|
521
|
+
|
|
522
|
+
while elapsed < maxWaitSeconds:
|
|
523
|
+
result = await client.GET(f"/api/v1/analysis/{sessionId}")
|
|
524
|
+
|
|
525
|
+
if result.status == "completed":
|
|
526
|
+
return result.summary
|
|
527
|
+
if result.status == "failed":
|
|
528
|
+
throw AnalysisFailedException(result.message)
|
|
529
|
+
|
|
530
|
+
await sleep(interval)
|
|
531
|
+
elapsed += interval
|
|
532
|
+
interval = min(interval * 1.5, 30) // cap at 30 seconds
|
|
533
|
+
|
|
534
|
+
throw AnalysisTimeoutException(sessionId)
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
---
|
|
538
|
+
|
|
539
|
+
## 9. Suggested Project Structures
|
|
540
|
+
|
|
541
|
+
### Python
|
|
542
|
+
```
|
|
543
|
+
chatbot_integration/
|
|
544
|
+
__init__.py
|
|
545
|
+
client.py # ChatbotHttpClient
|
|
546
|
+
auth.py # AuthService
|
|
547
|
+
session.py # SessionManager
|
|
548
|
+
chat.py # ChatService
|
|
549
|
+
escalation.py # EscalationHandler
|
|
550
|
+
analysis.py # AnalysisService (optional)
|
|
551
|
+
errors.py # Exception hierarchy + error strategies
|
|
552
|
+
models.py # DTOs / dataclasses
|
|
553
|
+
config.py # Configuration
|
|
554
|
+
tests/
|
|
555
|
+
test_auth.py
|
|
556
|
+
test_session.py
|
|
557
|
+
test_chat.py
|
|
558
|
+
```
|
|
559
|
+
|
|
560
|
+
### Java (Spring Boot)
|
|
561
|
+
```
|
|
562
|
+
src/main/java/com/vendor/chatbot/
|
|
563
|
+
client/
|
|
564
|
+
ChatbotHttpClient.java
|
|
565
|
+
service/
|
|
566
|
+
AuthService.java
|
|
567
|
+
SessionManager.java
|
|
568
|
+
ChatService.java
|
|
569
|
+
EscalationHandler.java
|
|
570
|
+
AnalysisService.java
|
|
571
|
+
model/
|
|
572
|
+
ApiResponse.java
|
|
573
|
+
AuthData.java
|
|
574
|
+
ChatResponse.java
|
|
575
|
+
exception/
|
|
576
|
+
ChatbotApiException.java
|
|
577
|
+
(subclasses)
|
|
578
|
+
config/
|
|
579
|
+
ChatbotConfig.java
|
|
580
|
+
ResilienceConfig.java
|
|
581
|
+
```
|
|
582
|
+
|
|
583
|
+
### C# (ASP.NET Core)
|
|
584
|
+
```
|
|
585
|
+
ChatbotIntegration/
|
|
586
|
+
Clients/
|
|
587
|
+
ChatbotHttpClient.cs
|
|
588
|
+
Services/
|
|
589
|
+
AuthService.cs
|
|
590
|
+
SessionManager.cs
|
|
591
|
+
ChatService.cs
|
|
592
|
+
IEscalationHandler.cs
|
|
593
|
+
AnalysisService.cs
|
|
594
|
+
Models/
|
|
595
|
+
ApiResponse.cs
|
|
596
|
+
DTOs/
|
|
597
|
+
Exceptions/
|
|
598
|
+
ChatbotApiException.cs
|
|
599
|
+
(subclasses)
|
|
600
|
+
Configuration/
|
|
601
|
+
ChatbotOptions.cs
|
|
602
|
+
DependencyInjection.cs
|
|
603
|
+
```
|
|
604
|
+
|
|
605
|
+
### Node.js (TypeScript)
|
|
606
|
+
```
|
|
607
|
+
src/
|
|
608
|
+
client/
|
|
609
|
+
chatbot-http-client.ts
|
|
610
|
+
services/
|
|
611
|
+
auth.service.ts
|
|
612
|
+
session.service.ts
|
|
613
|
+
chat.service.ts
|
|
614
|
+
escalation.handler.ts
|
|
615
|
+
analysis.service.ts
|
|
616
|
+
models/
|
|
617
|
+
api-response.ts
|
|
618
|
+
dtos.ts
|
|
619
|
+
errors/
|
|
620
|
+
chatbot-api.error.ts
|
|
621
|
+
(subclasses)
|
|
622
|
+
config/
|
|
623
|
+
chatbot.config.ts
|
|
624
|
+
index.ts
|
|
625
|
+
```
|