triagent 0.1.0-alpha10 → 0.1.0-alpha12
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 +38 -1
- package/package.json +6 -2
- package/src/cli/config.ts +22 -2
- package/src/config.ts +23 -3
- package/src/index.ts +9 -2
- package/src/mastra/agents/debugger.ts +11 -2
- package/src/mastra/index.ts +2 -2
- package/src/sandbox/bashlet.ts +12 -5
package/README.md
CHANGED
|
@@ -57,9 +57,46 @@ triagent config path
|
|
|
57
57
|
| `apiKey` | API key for the provider | - |
|
|
58
58
|
| `baseUrl` | Custom API base URL (for proxies or local models) | - |
|
|
59
59
|
| `webhookPort` | Webhook server port | `3000` |
|
|
60
|
-
| `codebasePath` | Path to codebase | `./` |
|
|
60
|
+
| `codebasePath` | Path to single codebase (legacy) | `./` |
|
|
61
61
|
| `kubeConfigPath` | Kubernetes config path | `~/.kube` |
|
|
62
62
|
|
|
63
|
+
### Multiple Codebases
|
|
64
|
+
|
|
65
|
+
For applications spanning multiple repositories, configure `codebasePaths` in `~/.config/triagent/config.json`:
|
|
66
|
+
|
|
67
|
+
```json
|
|
68
|
+
{
|
|
69
|
+
"codebasePaths": [
|
|
70
|
+
{ "name": "frontend", "path": "/path/to/frontend-repo" },
|
|
71
|
+
{ "name": "backend", "path": "/path/to/backend-repo" },
|
|
72
|
+
{ "name": "infra", "path": "/path/to/infrastructure" }
|
|
73
|
+
]
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Each codebase is mounted at `/workspace/<name>` in the sandbox. The model can access any codebase as needed during investigation.
|
|
78
|
+
|
|
79
|
+
### Custom Instructions (TRIAGENT.md)
|
|
80
|
+
|
|
81
|
+
Create `~/.config/triagent/TRIAGENT.md` to provide custom instructions to the model. These instructions are prepended to the default system prompt.
|
|
82
|
+
|
|
83
|
+
Example `TRIAGENT.md`:
|
|
84
|
+
|
|
85
|
+
```markdown
|
|
86
|
+
## Project Context
|
|
87
|
+
|
|
88
|
+
This is a microservices e-commerce platform with the following services:
|
|
89
|
+
- frontend: Next.js app in /workspace/frontend
|
|
90
|
+
- api: Go backend in /workspace/backend
|
|
91
|
+
- infra: Terraform configs in /workspace/infra
|
|
92
|
+
|
|
93
|
+
## Investigation Priorities
|
|
94
|
+
|
|
95
|
+
1. Always check the api service logs first for 5xx errors
|
|
96
|
+
2. The frontend service talks to api via internal DNS: api.default.svc.cluster.local
|
|
97
|
+
3. Common issues: Redis connection timeouts, PostgreSQL connection pool exhaustion
|
|
98
|
+
```
|
|
99
|
+
|
|
63
100
|
### Environment Variables
|
|
64
101
|
|
|
65
102
|
| Variable | Description |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "triagent",
|
|
3
|
-
"version": "0.1.0-
|
|
3
|
+
"version": "0.1.0-alpha12",
|
|
4
4
|
"description": "AI-powered Kubernetes debugging agent with terminal UI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.ts",
|
|
@@ -27,7 +27,11 @@
|
|
|
27
27
|
],
|
|
28
28
|
"repository": {
|
|
29
29
|
"type": "git",
|
|
30
|
-
"url": "git+https://github.com/
|
|
30
|
+
"url": "git+https://github.com/ServiceWeave/triagent.git"
|
|
31
|
+
},
|
|
32
|
+
"homepage": "https://github.com/ServiceWeave/triagent#readme",
|
|
33
|
+
"bugs": {
|
|
34
|
+
"url": "https://github.com/ServiceWeave/triagent/issues"
|
|
31
35
|
},
|
|
32
36
|
"license": "MIT",
|
|
33
37
|
"scripts": {
|
package/src/cli/config.ts
CHANGED
|
@@ -3,23 +3,43 @@ import { homedir } from "os";
|
|
|
3
3
|
import { join } from "path";
|
|
4
4
|
import type { AIProvider } from "../config.js";
|
|
5
5
|
|
|
6
|
+
export interface CodebaseEntry {
|
|
7
|
+
name: string;
|
|
8
|
+
path: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
6
11
|
export interface StoredConfig {
|
|
7
12
|
aiProvider?: AIProvider;
|
|
8
13
|
aiModel?: string;
|
|
9
14
|
apiKey?: string;
|
|
10
15
|
baseUrl?: string;
|
|
11
16
|
webhookPort?: number;
|
|
12
|
-
codebasePath?: string;
|
|
17
|
+
codebasePath?: string; // Deprecated: use codebasePaths instead
|
|
18
|
+
codebasePaths?: CodebaseEntry[];
|
|
13
19
|
kubeConfigPath?: string;
|
|
14
20
|
}
|
|
15
21
|
|
|
16
22
|
const CONFIG_DIR = join(homedir(), ".config", "triagent");
|
|
17
23
|
const CONFIG_FILE = join(CONFIG_DIR, "config.json");
|
|
24
|
+
const TRIAGENT_MD_FILE = join(CONFIG_DIR, "TRIAGENT.md");
|
|
18
25
|
|
|
19
26
|
export async function getConfigPath(): Promise<string> {
|
|
20
27
|
return CONFIG_FILE;
|
|
21
28
|
}
|
|
22
29
|
|
|
30
|
+
export async function getTriagentMdPath(): Promise<string> {
|
|
31
|
+
return TRIAGENT_MD_FILE;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export async function loadTriagentMd(): Promise<string | null> {
|
|
35
|
+
try {
|
|
36
|
+
const content = await readFile(TRIAGENT_MD_FILE, "utf-8");
|
|
37
|
+
return content.trim();
|
|
38
|
+
} catch {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
23
43
|
export async function loadStoredConfig(): Promise<StoredConfig> {
|
|
24
44
|
try {
|
|
25
45
|
const content = await readFile(CONFIG_FILE, "utf-8");
|
|
@@ -40,7 +60,7 @@ export async function setConfigValue(key: keyof StoredConfig, value: string | nu
|
|
|
40
60
|
await saveStoredConfig(config);
|
|
41
61
|
}
|
|
42
62
|
|
|
43
|
-
export async function getConfigValue(key: keyof StoredConfig): Promise<
|
|
63
|
+
export async function getConfigValue(key: keyof StoredConfig): Promise<StoredConfig[keyof StoredConfig]> {
|
|
44
64
|
const config = await loadStoredConfig();
|
|
45
65
|
return config[key];
|
|
46
66
|
}
|
package/src/config.ts
CHANGED
|
@@ -1,22 +1,28 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { resolve } from "path";
|
|
3
3
|
import { homedir } from "os";
|
|
4
|
-
import { loadStoredConfig, type StoredConfig } from "./cli/config.js";
|
|
4
|
+
import { loadStoredConfig, type StoredConfig, type CodebaseEntry } from "./cli/config.js";
|
|
5
5
|
|
|
6
6
|
const AIProviderSchema = z.enum(["openai", "anthropic", "google"]);
|
|
7
7
|
export type AIProvider = z.infer<typeof AIProviderSchema>;
|
|
8
8
|
|
|
9
|
+
const CodebaseEntrySchema = z.object({
|
|
10
|
+
name: z.string().min(1),
|
|
11
|
+
path: z.string().min(1),
|
|
12
|
+
});
|
|
13
|
+
|
|
9
14
|
const ConfigSchema = z.object({
|
|
10
15
|
aiProvider: AIProviderSchema,
|
|
11
16
|
aiModel: z.string().min(1),
|
|
12
17
|
apiKey: z.string().min(1),
|
|
13
18
|
baseUrl: z.string().url().optional(),
|
|
14
19
|
webhookPort: z.number().int().positive().default(3000),
|
|
15
|
-
|
|
20
|
+
codebasePaths: z.array(CodebaseEntrySchema).min(1),
|
|
16
21
|
kubeConfigPath: z.string().min(1).default("~/.kube"),
|
|
17
22
|
});
|
|
18
23
|
|
|
19
24
|
export type Config = z.infer<typeof ConfigSchema>;
|
|
25
|
+
export type { CodebaseEntry };
|
|
20
26
|
|
|
21
27
|
function expandPath(path: string): string {
|
|
22
28
|
if (path.startsWith("~")) {
|
|
@@ -39,6 +45,20 @@ function getApiKey(provider: AIProvider, stored: StoredConfig): string {
|
|
|
39
45
|
}
|
|
40
46
|
}
|
|
41
47
|
|
|
48
|
+
function resolveCodebasePaths(stored: StoredConfig): CodebaseEntry[] {
|
|
49
|
+
// Priority: codebasePaths array > legacy codebasePath > default
|
|
50
|
+
if (stored.codebasePaths && stored.codebasePaths.length > 0) {
|
|
51
|
+
return stored.codebasePaths.map((entry) => ({
|
|
52
|
+
name: entry.name,
|
|
53
|
+
path: expandPath(entry.path),
|
|
54
|
+
}));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Backward compatibility: convert single codebasePath to array
|
|
58
|
+
const legacyPath = process.env.CODEBASE_PATH || stored.codebasePath || "./";
|
|
59
|
+
return [{ name: "workspace", path: expandPath(legacyPath) }];
|
|
60
|
+
}
|
|
61
|
+
|
|
42
62
|
export async function loadConfig(): Promise<Config> {
|
|
43
63
|
const stored = await loadStoredConfig();
|
|
44
64
|
|
|
@@ -50,7 +70,7 @@ export async function loadConfig(): Promise<Config> {
|
|
|
50
70
|
apiKey: getApiKey(provider, stored),
|
|
51
71
|
baseUrl: process.env.AI_BASE_URL || stored.baseUrl || undefined,
|
|
52
72
|
webhookPort: parseInt(process.env.WEBHOOK_PORT || String(stored.webhookPort || 3000), 10),
|
|
53
|
-
|
|
73
|
+
codebasePaths: resolveCodebasePaths(stored),
|
|
54
74
|
kubeConfigPath: expandPath(process.env.KUBE_CONFIG_PATH || stored.kubeConfigPath || "~/.kube"),
|
|
55
75
|
};
|
|
56
76
|
|
package/src/index.ts
CHANGED
|
@@ -88,9 +88,16 @@ CONFIG KEYS:
|
|
|
88
88
|
apiKey - API key for the provider
|
|
89
89
|
baseUrl - Custom API base URL (for proxies or local models)
|
|
90
90
|
webhookPort - Webhook server port (default: 3000)
|
|
91
|
-
codebasePath - Path to codebase (default: ./)
|
|
91
|
+
codebasePath - Path to codebase (default: ./) - for single codebase
|
|
92
92
|
kubeConfigPath - Kubernetes config path (default: ~/.kube)
|
|
93
93
|
|
|
94
|
+
For multiple codebases, edit ~/.config/triagent/config.json directly:
|
|
95
|
+
"codebasePaths": [
|
|
96
|
+
{ "name": "frontend", "path": "/path/to/frontend" },
|
|
97
|
+
{ "name": "backend", "path": "/path/to/backend" }
|
|
98
|
+
]
|
|
99
|
+
Each codebase will be mounted at /workspace/<name> in the sandbox.
|
|
100
|
+
|
|
94
101
|
MODES:
|
|
95
102
|
Interactive (default):
|
|
96
103
|
Run with no arguments to start the interactive TUI.
|
|
@@ -280,7 +287,7 @@ async function main(): Promise<void> {
|
|
|
280
287
|
// Initialize sandbox and Mastra
|
|
281
288
|
try {
|
|
282
289
|
initSandboxFromConfig(config, args.host);
|
|
283
|
-
createMastraInstance(config);
|
|
290
|
+
await createMastraInstance(config);
|
|
284
291
|
if (args.host) {
|
|
285
292
|
console.log("⚠️ Running in host mode (no sandbox)\n");
|
|
286
293
|
}
|
|
@@ -3,6 +3,7 @@ import { z } from "zod";
|
|
|
3
3
|
import { cliTool } from "../tools/cli.js";
|
|
4
4
|
import { gitTool } from "../tools/git.js";
|
|
5
5
|
import { filesystemTool } from "../tools/filesystem.js";
|
|
6
|
+
import { loadTriagentMd } from "../../cli/config.js";
|
|
6
7
|
import type { Config } from "../../config.js";
|
|
7
8
|
|
|
8
9
|
const DEBUGGER_INSTRUCTIONS = `You are an expert Kubernetes debugging agent named Triagent. Your role is to investigate and diagnose issues in Kubernetes clusters by analyzing resources, logs, code, and git history.
|
|
@@ -162,7 +163,15 @@ export const InvestigationResultSchema = z.object({
|
|
|
162
163
|
|
|
163
164
|
export type InvestigationResult = z.infer<typeof InvestigationResultSchema>;
|
|
164
165
|
|
|
165
|
-
export function createDebuggerAgent(config: Config) {
|
|
166
|
+
export async function createDebuggerAgent(config: Config) {
|
|
167
|
+
// Load user instructions from ~/.config/triagent/TRIAGENT.md if present
|
|
168
|
+
const userInstructions = await loadTriagentMd();
|
|
169
|
+
|
|
170
|
+
// Combine user instructions with default instructions
|
|
171
|
+
const instructions = userInstructions
|
|
172
|
+
? `## User-Provided Instructions\n\n${userInstructions}\n\n---\n\n${DEBUGGER_INSTRUCTIONS}`
|
|
173
|
+
: DEBUGGER_INSTRUCTIONS;
|
|
174
|
+
|
|
166
175
|
// Construct model config with API key and optional base URL
|
|
167
176
|
const modelId = `${config.aiProvider}/${config.aiModel}` as const;
|
|
168
177
|
const modelConfig = {
|
|
@@ -174,7 +183,7 @@ export function createDebuggerAgent(config: Config) {
|
|
|
174
183
|
return new Agent({
|
|
175
184
|
id: "kubernetes-debugger",
|
|
176
185
|
name: "Kubernetes Debugger",
|
|
177
|
-
instructions
|
|
186
|
+
instructions,
|
|
178
187
|
model: modelConfig as any, // Mastra handles model routing
|
|
179
188
|
tools: {
|
|
180
189
|
cli: cliTool,
|
package/src/mastra/index.ts
CHANGED
|
@@ -4,12 +4,12 @@ import type { Config } from "../config.js";
|
|
|
4
4
|
|
|
5
5
|
let mastraInstance: Mastra | null = null;
|
|
6
6
|
|
|
7
|
-
export function createMastraInstance(config: Config): Mastra {
|
|
7
|
+
export async function createMastraInstance(config: Config): Promise<Mastra> {
|
|
8
8
|
if (mastraInstance) {
|
|
9
9
|
return mastraInstance;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
const debuggerAgent = createDebuggerAgent(config);
|
|
12
|
+
const debuggerAgent = await createDebuggerAgent(config);
|
|
13
13
|
|
|
14
14
|
mastraInstance = new Mastra({
|
|
15
15
|
agents: {
|
package/src/sandbox/bashlet.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Bashlet } from "@bashlet/sdk";
|
|
2
2
|
import { $ } from "bun";
|
|
3
3
|
import { readFile as fsReadFile, readdir } from "fs/promises";
|
|
4
|
-
import type { Config } from "../config.js";
|
|
4
|
+
import type { Config, CodebaseEntry } from "../config.js";
|
|
5
5
|
|
|
6
6
|
export interface CommandResult {
|
|
7
7
|
stdout: string;
|
|
@@ -10,7 +10,7 @@ export interface CommandResult {
|
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
export interface SandboxOptions {
|
|
13
|
-
|
|
13
|
+
codebasePaths: CodebaseEntry[];
|
|
14
14
|
kubeConfigPath: string;
|
|
15
15
|
timeout?: number;
|
|
16
16
|
useHost?: boolean;
|
|
@@ -22,7 +22,8 @@ let hostWorkdir = "./";
|
|
|
22
22
|
|
|
23
23
|
export function createSandbox(options: SandboxOptions): void {
|
|
24
24
|
hostMode = options.useHost ?? false;
|
|
25
|
-
|
|
25
|
+
// Use first codebase as default working directory
|
|
26
|
+
hostWorkdir = options.codebasePaths[0]?.path || "./";
|
|
26
27
|
|
|
27
28
|
if (hostMode) {
|
|
28
29
|
return;
|
|
@@ -32,9 +33,15 @@ export function createSandbox(options: SandboxOptions): void {
|
|
|
32
33
|
return;
|
|
33
34
|
}
|
|
34
35
|
|
|
36
|
+
// Mount each codebase at /workspace/<name>
|
|
37
|
+
const codebaseMounts = options.codebasePaths.map((entry) => ({
|
|
38
|
+
hostPath: entry.path,
|
|
39
|
+
guestPath: `/workspace/${entry.name}`,
|
|
40
|
+
}));
|
|
41
|
+
|
|
35
42
|
bashletInstance = new Bashlet({
|
|
36
43
|
mounts: [
|
|
37
|
-
|
|
44
|
+
...codebaseMounts,
|
|
38
45
|
{ hostPath: options.kubeConfigPath, guestPath: "/root/.kube" },
|
|
39
46
|
],
|
|
40
47
|
workdir: "/workspace",
|
|
@@ -143,7 +150,7 @@ export async function listDir(path: string): Promise<string[]> {
|
|
|
143
150
|
|
|
144
151
|
export function initSandboxFromConfig(config: Config, useHost: boolean = false): void {
|
|
145
152
|
createSandbox({
|
|
146
|
-
|
|
153
|
+
codebasePaths: config.codebasePaths,
|
|
147
154
|
kubeConfigPath: config.kubeConfigPath,
|
|
148
155
|
timeout: 120,
|
|
149
156
|
useHost,
|