@ebowwa/ai 0.1.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.
@@ -0,0 +1,222 @@
1
+ /**
2
+ * Composable prompt architecture for scalable AI interactions
3
+ *
4
+ * Core concepts:
5
+ * - PromptPart: Composable building blocks
6
+ * - PromptBuilder: Fluent API for assembling prompts
7
+ * - PromptTemplate: Reusable templates with interpolation
8
+ * - PromptChain: Multi-step workflows
9
+ * - PromptStrategy: Different reasoning approaches
10
+ */
11
+ import type { ChatMessage } from "./types.js";
12
+ export type { ChatMessage };
13
+ /**
14
+ * Base interface for all composable prompt parts
15
+ */
16
+ export interface PromptPart {
17
+ toPrompt(): string;
18
+ }
19
+ /**
20
+ * System instruction - sets AI role and behavior
21
+ */
22
+ export declare class SystemInstruction implements PromptPart {
23
+ role: string;
24
+ guidelines?: string[] | undefined;
25
+ constructor(role: string, guidelines?: string[] | undefined);
26
+ toPrompt(): string;
27
+ }
28
+ /**
29
+ * Context - provides data/background information
30
+ */
31
+ export declare class Context implements PromptPart {
32
+ data: Record<string, unknown>;
33
+ constructor(data: Record<string, unknown>);
34
+ toPrompt(): string;
35
+ }
36
+ /**
37
+ * Examples - few-shot learning samples
38
+ */
39
+ export declare class Examples implements PromptPart {
40
+ examples: Array<{
41
+ input: string;
42
+ output: string;
43
+ }>;
44
+ constructor(examples: Array<{
45
+ input: string;
46
+ output: string;
47
+ }>);
48
+ toPrompt(): string;
49
+ }
50
+ /**
51
+ * Output format specification
52
+ */
53
+ export declare class OutputFormat implements PromptPart {
54
+ type: "json" | "text" | "code" | "markdown";
55
+ schema?: Record<string, unknown> | undefined;
56
+ constructor(type: "json" | "text" | "code" | "markdown", schema?: Record<string, unknown> | undefined);
57
+ toPrompt(): string;
58
+ }
59
+ /**
60
+ * Constraints - rules and limitations
61
+ */
62
+ export declare class Constraints implements PromptPart {
63
+ rules: string[];
64
+ constructor(rules: string[]);
65
+ toPrompt(): string;
66
+ }
67
+ /**
68
+ * Task - the main instruction/question
69
+ */
70
+ export declare class Task implements PromptPart {
71
+ instruction: string;
72
+ constructor(instruction: string);
73
+ toPrompt(): string;
74
+ }
75
+ /**
76
+ * Fluent builder for composable prompts
77
+ */
78
+ export declare class PromptBuilder {
79
+ private parts;
80
+ private systemPart?;
81
+ /**
82
+ * Set system role and guidelines
83
+ */
84
+ system(role: string, guidelines?: string[]): this;
85
+ /**
86
+ * Add context data
87
+ */
88
+ context(data: Record<string, unknown>): this;
89
+ /**
90
+ * Add few-shot examples
91
+ */
92
+ examples(examples: Array<{
93
+ input: string;
94
+ output: string;
95
+ }>): this;
96
+ /**
97
+ * Specify output format
98
+ */
99
+ output(type: "json" | "text" | "code" | "markdown", schema?: Record<string, unknown>): this;
100
+ /**
101
+ * Add constraints/rules
102
+ */
103
+ constraints(...rules: string[]): this;
104
+ /**
105
+ * Add the main task/instruction
106
+ */
107
+ task(instruction: string): this;
108
+ /**
109
+ * Add custom prompt part
110
+ */
111
+ custom(part: PromptPart): this;
112
+ /**
113
+ * Build final prompt string (for simple generate)
114
+ */
115
+ build(): string;
116
+ /**
117
+ * Build for chat completion (returns messages array)
118
+ */
119
+ buildChat(): ChatMessage[];
120
+ /**
121
+ * Build as system + user prompt pair
122
+ */
123
+ buildPair(): {
124
+ system: string;
125
+ user: string;
126
+ };
127
+ }
128
+ /**
129
+ * Reusable prompt template with variable interpolation
130
+ */
131
+ export declare class PromptTemplate {
132
+ private template;
133
+ constructor(template: string);
134
+ /**
135
+ * Render template with variables
136
+ * Supports {{variable}} syntax
137
+ */
138
+ render(vars: Record<string, unknown>): string;
139
+ /**
140
+ * Create template from string
141
+ */
142
+ static from(template: string): PromptTemplate;
143
+ /**
144
+ * Create typed template with compile-time safety
145
+ */
146
+ static typed<T extends Record<string, unknown>>(template: string): TypedPromptTemplate<T>;
147
+ }
148
+ /**
149
+ * Type-safe prompt template
150
+ */
151
+ export declare class TypedPromptTemplate<T extends Record<string, unknown>> {
152
+ private template;
153
+ constructor(template: string);
154
+ render(vars: T): string;
155
+ }
156
+ /**
157
+ * Prompt strategies for different reasoning approaches
158
+ */
159
+ export declare class PromptStrategy {
160
+ /**
161
+ * Zero-shot: direct instruction without examples
162
+ */
163
+ static zeroShot(instruction: string): string;
164
+ /**
165
+ * Few-shot: instruction with examples
166
+ */
167
+ static fewShot(instruction: string, examples: Array<{
168
+ input: string;
169
+ output: string;
170
+ }>): string;
171
+ /**
172
+ * Chain-of-thought: step-by-step reasoning
173
+ */
174
+ static chainOfThought(question: string): string;
175
+ /**
176
+ * ReAct: Reasoning + Acting (for tool use)
177
+ */
178
+ static reAct(task: string): string;
179
+ }
180
+ /**
181
+ * Chain prompts where output feeds into next input
182
+ */
183
+ export declare class PromptChain {
184
+ private steps;
185
+ /**
186
+ * Add a step to the chain
187
+ */
188
+ add(step: (input: string, client: any) => Promise<string>): this;
189
+ /**
190
+ * Execute the entire chain
191
+ */
192
+ execute(initialInput: string, client: any): Promise<string[]>;
193
+ }
194
+ /**
195
+ * Pre-built prompt templates for common AI tasks
196
+ */
197
+ export declare const PROMPTS: {
198
+ /**
199
+ * Generate a server name based on project context
200
+ */
201
+ readonly generateServerName: (project?: string, description?: string) => string;
202
+ /**
203
+ * Suggest optimal server type based on workload
204
+ */
205
+ readonly suggestServerType: (workload: string) => string;
206
+ /**
207
+ * Analyze resource usage and provide recommendations
208
+ */
209
+ readonly analyzeResources: (cpu: number, memory: number, disk: number, activePorts?: string[]) => string;
210
+ /**
211
+ * Generate SSH troubleshooting tips
212
+ */
213
+ readonly sshTroubleshoot: (error: string) => string;
214
+ /**
215
+ * Suggest server actions based on state
216
+ */
217
+ readonly suggestActions: (status: string, age?: string) => string;
218
+ /**
219
+ * Generate a witty server status message
220
+ */
221
+ readonly statusMessage: (status: string, name: string) => string;
222
+ };
@@ -0,0 +1,462 @@
1
+ /**
2
+ * Composable prompt architecture for scalable AI interactions
3
+ *
4
+ * Core concepts:
5
+ * - PromptPart: Composable building blocks
6
+ * - PromptBuilder: Fluent API for assembling prompts
7
+ * - PromptTemplate: Reusable templates with interpolation
8
+ * - PromptChain: Multi-step workflows
9
+ * - PromptStrategy: Different reasoning approaches
10
+ */
11
+ /**
12
+ * System instruction - sets AI role and behavior
13
+ */
14
+ export class SystemInstruction {
15
+ role;
16
+ guidelines;
17
+ constructor(role, guidelines) {
18
+ this.role = role;
19
+ this.guidelines = guidelines;
20
+ }
21
+ toPrompt() {
22
+ const base = `You are a ${this.role}.`;
23
+ if (this.guidelines?.length) {
24
+ return `${base}\n\nGuidelines:\n${this.guidelines.map((g) => `- ${g}`).join("\n")}`;
25
+ }
26
+ return base;
27
+ }
28
+ }
29
+ /**
30
+ * Context - provides data/background information
31
+ */
32
+ export class Context {
33
+ data;
34
+ constructor(data) {
35
+ this.data = data;
36
+ }
37
+ toPrompt() {
38
+ const entries = Object.entries(this.data)
39
+ .filter(([_, v]) => v !== undefined && v !== null && v !== "")
40
+ .map(([k, v]) => `- ${k}: ${typeof v === "object" ? JSON.stringify(v) : v}`)
41
+ .join("\n");
42
+ return entries ? `Context:\n${entries}` : "";
43
+ }
44
+ }
45
+ /**
46
+ * Examples - few-shot learning samples
47
+ */
48
+ export class Examples {
49
+ examples;
50
+ constructor(examples) {
51
+ this.examples = examples;
52
+ }
53
+ toPrompt() {
54
+ if (this.examples.length === 0)
55
+ return "";
56
+ return this.examples
57
+ .map((ex, i) => `Example ${i + 1}:\nInput: ${ex.input}\nOutput: ${ex.output}`)
58
+ .join("\n\n");
59
+ }
60
+ }
61
+ /**
62
+ * Output format specification
63
+ */
64
+ export class OutputFormat {
65
+ type;
66
+ schema;
67
+ constructor(type, schema) {
68
+ this.type = type;
69
+ this.schema = schema;
70
+ }
71
+ toPrompt() {
72
+ if (this.type === "json" && this.schema) {
73
+ return `Respond in JSON format with this schema:\n${JSON.stringify(this.schema, null, 2)}`;
74
+ }
75
+ return `Respond in ${this.type} format.`;
76
+ }
77
+ }
78
+ /**
79
+ * Constraints - rules and limitations
80
+ */
81
+ export class Constraints {
82
+ rules;
83
+ constructor(rules) {
84
+ this.rules = rules;
85
+ }
86
+ toPrompt() {
87
+ if (this.rules.length === 0)
88
+ return "";
89
+ return `Constraints:\n${this.rules.map((r) => `- ${r}`).join("\n")}`;
90
+ }
91
+ }
92
+ /**
93
+ * Task - the main instruction/question
94
+ */
95
+ export class Task {
96
+ instruction;
97
+ constructor(instruction) {
98
+ this.instruction = instruction;
99
+ }
100
+ toPrompt() {
101
+ return `Task:\n${this.instruction}`;
102
+ }
103
+ }
104
+ /**
105
+ * Fluent builder for composable prompts
106
+ */
107
+ export class PromptBuilder {
108
+ parts = [];
109
+ systemPart;
110
+ /**
111
+ * Set system role and guidelines
112
+ */
113
+ system(role, guidelines) {
114
+ this.systemPart = new SystemInstruction(role, guidelines);
115
+ return this;
116
+ }
117
+ /**
118
+ * Add context data
119
+ */
120
+ context(data) {
121
+ this.parts.push(new Context(data));
122
+ return this;
123
+ }
124
+ /**
125
+ * Add few-shot examples
126
+ */
127
+ examples(examples) {
128
+ this.parts.push(new Examples(examples));
129
+ return this;
130
+ }
131
+ /**
132
+ * Specify output format
133
+ */
134
+ output(type, schema) {
135
+ this.parts.push(new OutputFormat(type, schema));
136
+ return this;
137
+ }
138
+ /**
139
+ * Add constraints/rules
140
+ */
141
+ constraints(...rules) {
142
+ this.parts.push(new Constraints(rules));
143
+ return this;
144
+ }
145
+ /**
146
+ * Add the main task/instruction
147
+ */
148
+ task(instruction) {
149
+ this.parts.push(new Task(instruction));
150
+ return this;
151
+ }
152
+ /**
153
+ * Add custom prompt part
154
+ */
155
+ custom(part) {
156
+ this.parts.push(part);
157
+ return this;
158
+ }
159
+ /**
160
+ * Build final prompt string (for simple generate)
161
+ */
162
+ build() {
163
+ const allParts = [
164
+ ...(this.systemPart ? [this.systemPart] : []),
165
+ ...this.parts,
166
+ ];
167
+ return allParts
168
+ .map((p) => p.toPrompt())
169
+ .filter(Boolean)
170
+ .join("\n\n");
171
+ }
172
+ /**
173
+ * Build for chat completion (returns messages array)
174
+ */
175
+ buildChat() {
176
+ const messages = [];
177
+ if (this.systemPart) {
178
+ messages.push({ role: "system", content: this.systemPart.toPrompt() });
179
+ }
180
+ const userContent = this.parts
181
+ .map((p) => p.toPrompt())
182
+ .filter(Boolean)
183
+ .join("\n\n");
184
+ if (userContent) {
185
+ messages.push({ role: "user", content: userContent });
186
+ }
187
+ return messages;
188
+ }
189
+ /**
190
+ * Build as system + user prompt pair
191
+ */
192
+ buildPair() {
193
+ return {
194
+ system: this.systemPart?.toPrompt() || "",
195
+ user: this.parts
196
+ .map((p) => p.toPrompt())
197
+ .filter(Boolean)
198
+ .join("\n\n"),
199
+ };
200
+ }
201
+ }
202
+ /**
203
+ * Reusable prompt template with variable interpolation
204
+ */
205
+ export class PromptTemplate {
206
+ template;
207
+ constructor(template) {
208
+ this.template = template;
209
+ }
210
+ /**
211
+ * Render template with variables
212
+ * Supports {{variable}} syntax
213
+ */
214
+ render(vars) {
215
+ let result = this.template;
216
+ for (const [key, value] of Object.entries(vars)) {
217
+ const placeholder = `{{${key}}}`;
218
+ result = result.replaceAll(placeholder, String(value ?? ""));
219
+ }
220
+ return result;
221
+ }
222
+ /**
223
+ * Create template from string
224
+ */
225
+ static from(template) {
226
+ return new PromptTemplate(template);
227
+ }
228
+ /**
229
+ * Create typed template with compile-time safety
230
+ */
231
+ static typed(template) {
232
+ return new TypedPromptTemplate(template);
233
+ }
234
+ }
235
+ /**
236
+ * Type-safe prompt template
237
+ */
238
+ export class TypedPromptTemplate {
239
+ template;
240
+ constructor(template) {
241
+ this.template = template;
242
+ }
243
+ render(vars) {
244
+ return new PromptTemplate(this.template).render(vars);
245
+ }
246
+ }
247
+ /**
248
+ * Prompt strategies for different reasoning approaches
249
+ */
250
+ export class PromptStrategy {
251
+ /**
252
+ * Zero-shot: direct instruction without examples
253
+ */
254
+ static zeroShot(instruction) {
255
+ return instruction;
256
+ }
257
+ /**
258
+ * Few-shot: instruction with examples
259
+ */
260
+ static fewShot(instruction, examples) {
261
+ return new PromptBuilder().examples(examples).task(instruction).build();
262
+ }
263
+ /**
264
+ * Chain-of-thought: step-by-step reasoning
265
+ */
266
+ static chainOfThought(question) {
267
+ return `${question}\n\nThink step by step. Show your work and reasoning process.`;
268
+ }
269
+ /**
270
+ * ReAct: Reasoning + Acting (for tool use)
271
+ */
272
+ static reAct(task) {
273
+ return `Task: ${task}
274
+
275
+ Think: [your reasoning about the current state]
276
+ Act: [action to take]
277
+ Observation: [result of action]
278
+
279
+ Repeat Think/Act/Observation until the task is complete.`;
280
+ }
281
+ }
282
+ /**
283
+ * Chain prompts where output feeds into next input
284
+ */
285
+ export class PromptChain {
286
+ steps = [];
287
+ /**
288
+ * Add a step to the chain
289
+ */
290
+ add(step) {
291
+ this.steps.push(step);
292
+ return this;
293
+ }
294
+ /**
295
+ * Execute the entire chain
296
+ */
297
+ async execute(initialInput, client) {
298
+ const results = [];
299
+ let current = initialInput;
300
+ for (const step of this.steps) {
301
+ current = await step(current, client);
302
+ results.push(current);
303
+ }
304
+ return results;
305
+ }
306
+ }
307
+ // ============================================================================
308
+ // PRE-BUILT PROMPTS (Refactored using composable architecture)
309
+ // ============================================================================
310
+ /**
311
+ * Pre-built prompt templates for common AI tasks
312
+ */
313
+ export const PROMPTS = {
314
+ /**
315
+ * Generate a server name based on project context
316
+ */
317
+ generateServerName: (project, description) => {
318
+ return new PromptBuilder()
319
+ .system("server naming specialist", [
320
+ "Create memorable, technical names",
321
+ "Use lowercase letters and hyphens only",
322
+ ])
323
+ .context({ project, description })
324
+ .constraints("8-15 characters maximum", "lowercase letters only", "hyphens allowed but no consecutive hyphens", "Return ONLY the name, no explanation")
325
+ .task("Generate a short, memorable server name.")
326
+ .build();
327
+ },
328
+ /**
329
+ * Suggest optimal server type based on workload
330
+ */
331
+ suggestServerType: (workload) => {
332
+ return new PromptBuilder()
333
+ .system("Hetzner cloud infrastructure expert", [
334
+ "Know all Hetzner server types and their capabilities",
335
+ "Consider cost-effectiveness",
336
+ ])
337
+ .context({ workload })
338
+ .examples([
339
+ {
340
+ input: "High-traffic web server with moderate CPU needs",
341
+ output: "cpx21 - Good balance of performance and cost for web workloads",
342
+ },
343
+ {
344
+ input: "Development/testing server",
345
+ output: "cpx11 - Lowest cost option, sufficient for development",
346
+ },
347
+ ])
348
+ .constraints("Respond with just the server type name", "Follow with one brief sentence explaining why", "Suggest any appropriate Hetzner server type based on the workload needs")
349
+ .task("Suggest the best Hetzner server type for this workload.")
350
+ .build();
351
+ },
352
+ /**
353
+ * Analyze resource usage and provide recommendations
354
+ */
355
+ analyzeResources: (cpu, memory, disk, activePorts) => {
356
+ const contextData = {
357
+ cpu: `${cpu}%`,
358
+ memory: `${memory}%`,
359
+ disk: `${disk}%`,
360
+ };
361
+ if (activePorts && activePorts.length > 0) {
362
+ contextData.activePorts =
363
+ activePorts.slice(0, 10).join(", ") +
364
+ (activePorts.length > 10 ? ` (+${activePorts.length - 10} more)` : "");
365
+ }
366
+ return new PromptBuilder()
367
+ .system("DevOps monitoring specialist", [
368
+ "Assess server health holistically",
369
+ "Prioritize actionable advice",
370
+ ])
371
+ .context(contextData)
372
+ .examples([
373
+ {
374
+ input: "CPU: 95%, Memory: 90%, Disk: 50%",
375
+ output: "CRITICAL: Immediate scale-up required. CPU and memory are at dangerous levels.",
376
+ },
377
+ {
378
+ input: "CPU: 15%, Memory: 25%, Disk: 30%",
379
+ output: "HEALTHY: All metrics within normal range. No action needed.",
380
+ },
381
+ {
382
+ input: "CPU: 45%, Memory: 85%, Disk: 20%",
383
+ output: "WARNING: Memory usage high. Consider optimizing applications or upgrading memory.",
384
+ },
385
+ ])
386
+ .constraints("Assessment must be one of: HEALTHY, WARNING, CRITICAL", "Provide exactly one sentence for assessment", "Provide exactly one actionable recommendation if not HEALTHY", "Keep total response under 100 words")
387
+ .task("Analyze the server resource usage and provide health assessment.")
388
+ .build();
389
+ },
390
+ /**
391
+ * Generate SSH troubleshooting tips
392
+ */
393
+ sshTroubleshoot: (error) => {
394
+ return new PromptBuilder()
395
+ .system("SSH troubleshooting expert", [
396
+ "Know common SSH issues and solutions",
397
+ "Provide practical, step-by-step solutions",
398
+ ])
399
+ .context({ error })
400
+ .examples([
401
+ {
402
+ input: "Connection refused",
403
+ output: "1. Verify SSH service is running: systemctl status sshd\n2. Check firewall rules\n3. Confirm correct port (usually 22)",
404
+ },
405
+ {
406
+ input: "Permission denied (publickey)",
407
+ output: "1. Verify public key is added to server's ~/.ssh/authorized_keys\n2. Check file permissions: chmod 700 ~/.ssh and chmod 600 ~/.ssh/authorized_keys\n3. Ensure you're using the correct private key",
408
+ },
409
+ ])
410
+ .constraints("Provide 2-3 specific troubleshooting steps", "Each step should be actionable", "Keep responses concise")
411
+ .task("Provide SSH troubleshooting steps for this error.")
412
+ .build();
413
+ },
414
+ /**
415
+ * Suggest server actions based on state
416
+ */
417
+ suggestActions: (status, age) => {
418
+ return new PromptBuilder()
419
+ .system("Server operations specialist", [
420
+ "Understand server lifecycle management",
421
+ "Consider cost implications",
422
+ ])
423
+ .context({ status, age })
424
+ .examples([
425
+ {
426
+ input: "Status: stopped, Age: 2 hours",
427
+ output: "Actions: start (to resume service), delete (if no longer needed)",
428
+ },
429
+ {
430
+ input: "Status: running, Age: 30 days",
431
+ output: "Actions: reboot (for maintenance), resize (if performance issues)",
432
+ },
433
+ ])
434
+ .constraints("Suggest 1-2 appropriate actions", "Include very brief explanation for each", "Consider actions: start, stop, restart, delete, resize")
435
+ .task("Suggest appropriate server management actions.")
436
+ .build();
437
+ },
438
+ /**
439
+ * Generate a witty server status message
440
+ */
441
+ statusMessage: (status, name) => {
442
+ return new PromptBuilder()
443
+ .system("Playful status message generator", [
444
+ "Be lighthearted but professional",
445
+ "Use puns and wordplay when appropriate",
446
+ ])
447
+ .context({ status, name })
448
+ .examples([
449
+ {
450
+ input: "Status: running, Name: prod-db-01",
451
+ output: "🟢 prod-db-01 is alive and kicking!",
452
+ },
453
+ {
454
+ input: "Status: stopped, Name: dev-server",
455
+ output: "💤 dev-server is taking a nap",
456
+ },
457
+ ])
458
+ .constraints("Keep under 50 characters", "Use appropriate emoji for status", "Be creative and memorable")
459
+ .task("Generate a brief, witty status message.")
460
+ .build();
461
+ },
462
+ };