@kairos-sdk/core 0.4.5 → 0.5.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # @kairos-sdk/core
2
2
 
3
- [![CI](https://github.com/Kruttz/kairos-sdk/actions/workflows/ci.yml/badge.svg)](https://github.com/Kruttz/kairos-sdk/actions/workflows/ci.yml)
3
+ [![CI](https://github.com/Kruttz/Kairos/actions/workflows/ci.yml/badge.svg)](https://github.com/Kruttz/Kairos/actions/workflows/ci.yml)
4
4
  [![npm version](https://img.shields.io/npm/v/@kairos-sdk/core)](https://www.npmjs.com/package/@kairos-sdk/core)
5
5
  [![npm downloads](https://img.shields.io/npm/dw/@kairos-sdk/core)](https://www.npmjs.com/package/@kairos-sdk/core)
6
6
 
@@ -8,7 +8,7 @@
8
8
 
9
9
  ![Kairos SDK Demo](demo.gif)
10
10
 
11
- Kairos turns plain-English workflow descriptions into validated, deployable n8n workflow JSON. Use it as an **MCP server** (connect to Claude Code, Claude Desktop, or any MCP host — your LLM generates, Kairos validates and deploys, no Anthropic API key needed) or as a **TypeScript SDK** for programmatic control (calls Claude internally with a specialized prompt). Either way, workflows pass through a **26-rule structural validator** with automatic correction, and a local workflow library with **hybrid retrieval** (TF-IDF + node fingerprinting + outcome history + cluster reranking) injects past failure patterns into future generations. With a seeded template library, Kairos achieves **100% first-try structural validation pass rate** across 20 benchmark prompts (meaning the generated JSON is structurally valid on the first attempt — runtime behavior depends on your credentials and node configuration).
11
+ Kairos turns plain-English workflow descriptions into validated, deployable n8n workflow JSON. Use it as an **MCP server** (connect to Claude Code, Claude Desktop, or any MCP host — your LLM generates, Kairos validates and deploys, no Anthropic API key needed) or as a **TypeScript SDK** for programmatic control (calls Claude internally with a specialized prompt). Either way, workflows pass through a **34-rule structural validator** with automatic correction, and a local workflow library with **hybrid retrieval** (TF-IDF + node fingerprinting + outcome history + cluster reranking) injects past failure patterns into future generations. With a seeded template library, Kairos achieves **100% first-try structural validation pass rate** across 20 benchmark prompts (meaning the generated JSON is structurally valid on the first attempt — runtime behavior depends on your credentials and node configuration).
12
12
 
13
13
  ```ts
14
14
  import { Kairos } from '@kairos-sdk/core'
@@ -32,7 +32,7 @@ console.log(result.credentialsNeeded) // what the user still needs to configure
32
32
  | Kairos does | Kairos does not guarantee (yet) |
33
33
  |---|---|
34
34
  | Generates valid n8n workflow JSON | Perfect business logic |
35
- | Validates structure before deploy (23 rules) | Correct credentials |
35
+ | Validates structure before deploy (34 rules) | Correct credentials |
36
36
  | Syncs node types from your live instance | Runtime success for every API |
37
37
  | Learns from prior successful builds | That every workflow matches intent perfectly |
38
38
  | Works through MCP, SDK, or CLI | Full replacement for human review |
@@ -95,7 +95,7 @@ The MCP server does **not** call an LLM internally. Instead, it gives your host
95
95
 
96
96
  1. **Host LLM calls `kairos_prompt`** — gets the n8n system prompt, node catalog, library matches, and failure patterns
97
97
  2. **Host LLM generates the workflow JSON** using that context (no separate API call)
98
- 3. **Host LLM calls `kairos_validate`** — checks the JSON against 26 structural rules
98
+ 3. **Host LLM calls `kairos_validate`** — checks the JSON against 34 structural rules
99
99
  4. If invalid, the host LLM fixes the issues and validates again
100
100
  5. **Host LLM calls `kairos_deploy`** — sends the validated workflow to n8n
101
101
 
@@ -108,15 +108,17 @@ This means Kairos works with **any LLM** — Claude, GPT, Gemini, Llama, or anyt
108
108
  | Tool | Description |
109
109
  |------|-------------|
110
110
  | `kairos_prompt` | Returns the specialized system prompt, node catalog, library matches, and failure patterns for a given description |
111
- | `kairos_validate` | Validates workflow JSON against 26 structural rules — returns errors and warnings |
111
+ | `kairos_validate` | Validates workflow JSON against 34 structural rules — returns errors and warnings |
112
112
  | `kairos_search` | Searches the local workflow library for similar past builds |
113
113
  | `kairos_sync` | Manually refresh the node catalog from your n8n instance (auto-runs on first `kairos_prompt` call) |
114
+ | `kairos_patterns` | Returns pattern analysis — top failure rules, confidence scores, and improvement suggestions derived from build telemetry |
114
115
 
115
116
  #### Deployment tools
116
117
 
117
118
  | Tool | Description |
118
119
  |------|-------------|
119
120
  | `kairos_deploy` | Deploys validated workflow JSON to n8n (re-validates before deploying) |
121
+ | `kairos_replace` | Replaces an existing n8n workflow with a new version — validates before updating, preserves workflow ID |
120
122
  | `kairos_list` | List all deployed workflows |
121
123
  | `kairos_get` | Get full workflow JSON by ID |
122
124
  | `kairos_activate` | Activate a workflow |
@@ -124,6 +126,13 @@ This means Kairos works with **any LLM** — Claude, GPT, Gemini, Llama, or anyt
124
126
  | `kairos_delete` | Delete a workflow |
125
127
  | `kairos_executions` | List recent executions with status |
126
128
 
129
+ #### Library tools
130
+
131
+ | Tool | Description |
132
+ |------|-------------|
133
+ | `kairos_library` | Browse or search the local Kairos workflow library — returns metadata, node counts, deploy history, and n8n workflow IDs |
134
+ | `kairos_outcome` | Record build outcome against a library entry — feeds the pattern learning system with attempt counts, failed rules, and generation mode |
135
+
127
136
  ---
128
137
 
129
138
  ## Use as SDK
@@ -180,7 +189,7 @@ console.log(deployed.workflowId) // now live in n8n
180
189
 
181
190
  ## Benchmark Results
182
191
 
183
- Tested against 20 workflow prompts of varying complexity (simple triggers, multi-step conditional logic, AI agents with memory). Results measure **structural validation pass rate** — whether the generated workflow passes all 26 validator rules, not end-to-end execution correctness.
192
+ Tested against 20 workflow prompts of varying complexity (simple triggers, multi-step conditional logic, AI agents with memory). Results measure **structural validation pass rate** — whether the generated workflow passes all 34 validator rules, not end-to-end execution correctness.
184
193
 
185
194
  ### Before vs After: Template-Seeded Library
186
195
 
@@ -192,7 +201,7 @@ Tested against 20 workflow prompts of varying complexity (simple triggers, multi
192
201
  | Avg generation time | 30.6s | **20.7s** | -32% |
193
202
  | Failures | 0 | 0 | — |
194
203
 
195
- The baseline run used Claude with the 26-rule validator and correction loop but no library. The seeded run used the same validator plus a library of 105 workflows (16 organic + 89 ingested from the n8n community). The broader local development library now contains 286+ generated/ingested workflows. Template seeding eliminated the correction loop entirely and cut generation time by a third.
204
+ The baseline run used Claude with the 34-rule validator and correction loop but no library. The seeded run used the same validator plus a library of 105 workflows (16 organic + 89 ingested from the n8n community). The broader local development library now contains 286+ generated/ingested workflows. Template seeding eliminated the correction loop entirely and cut generation time by a third.
196
205
 
197
206
  > **Note:** These results confirm that generated workflows are structurally valid and deployable to n8n. They do not verify runtime execution correctness, credential configuration, or whether the workflow output matches user intent.
198
207
 
@@ -205,7 +214,7 @@ The baseline run used Claude with the 26-rule validator and correction loop but
205
214
  1. **Search** — Kairos searches its local workflow library for similar past builds. Matching workflows and their failure patterns are pulled into context.
206
215
  2. **Warn** — Known failure patterns (from library matches and global telemetry rates) are injected into the system prompt so Claude avoids repeating known mistakes.
207
216
  3. **Generate** — Your description is sent to Claude with a detailed system prompt, forcing a `generate_workflow` tool call that produces structured n8n workflow JSON.
208
- 4. **Validate** — The workflow is checked against **26 structural rules** covering node IDs, types, versions, names, positions, connections, forbidden fields, trigger presence, AI connection direction, cycle detection, webhook pairing, and required parameters.
217
+ 4. **Validate** — The workflow is checked against **34 structural rules** covering node IDs, types, versions, names, positions, connections, forbidden fields, trigger presence, AI connection direction, cycle detection, webhook pairing, required parameters, and content quality (placeholder URLs, empty code nodes, missing required fields for Slack/Gmail/IF/Set/Schedule/Webhook nodes).
209
218
  5. **Correct** — If validation fails, the specific rule violations are sent back to Claude for correction (up to 3 attempts, with tighter temperature on the final try).
210
219
  6. **Strip** — Forbidden server-assigned fields (`id`, `createdAt`, `updatedAt`, etc.) are stripped before deployment.
211
220
  7. **Deploy** — The validated workflow is posted to your n8n instance via REST API.
@@ -215,7 +224,7 @@ The baseline run used Claude with the 26-rule validator and correction loop but
215
224
 
216
225
  1. **Prompt** — Your LLM calls `kairos_prompt`, which searches the library and returns the specialized system prompt, node catalog, library matches, and failure patterns.
217
226
  2. **Generate** — Your LLM generates the workflow JSON itself using that context. No separate API call.
218
- 3. **Validate** — Your LLM calls `kairos_validate`, which checks the JSON against the same 26 structural rules.
227
+ 3. **Validate** — Your LLM calls `kairos_validate`, which checks the JSON against the same 34 structural rules.
219
228
  4. **Correct** — If validation fails, your LLM fixes the issues and calls `kairos_validate` again.
220
229
  5. **Deploy** — Your LLM calls `kairos_deploy`, which strips forbidden fields and posts the workflow to n8n.
221
230
  6. **Record** — The deployed workflow is saved to the local library for future retrieval.
@@ -224,7 +233,7 @@ The baseline run used Claude with the 26-rule validator and correction loop but
224
233
 
225
234
  ## Validator Rules
226
235
 
227
- The 26-rule validator is the core of what makes Kairos reliable. In baseline testing (no library), Claude needed the correction loop 45% of the time. Each rule targets a specific class of error:
236
+ The 34-rule validator is the core of what makes Kairos reliable. In baseline testing (no library), Claude needed the correction loop 45% of the time. Each rule targets a specific class of error:
228
237
 
229
238
  | Rule | Severity | What it checks |
230
239
  |------|----------|----------------|
@@ -254,6 +263,14 @@ The 26-rule validator is the core of what makes Kairos reliable. In baseline tes
254
263
  | 24 | warn | No deprecated `$node["..."]` accessor syntax in expressions |
255
264
  | 25 | warn | No `$json.items[n]` array access (n8n flattens items automatically) |
256
265
  | 26 | warn | Node references use `.first()` or `.all()` (bare `$('Node').json` throws at runtime) |
266
+ | 27 | warn | HTTP Request URLs are real endpoints (not `example.com` or `YOUR_URL` placeholders) |
267
+ | 28 | warn | Code nodes contain actual executable logic (not empty or comment-only) |
268
+ | 29 | warn | Slack message operations specify a channel (`channelId` with `__rl` object, or `channel`) |
269
+ | 30 | warn | Gmail send operations specify at least one recipient (`to` field non-empty) |
270
+ | 31 | warn | IF nodes have at least one condition in `conditions.conditions` |
271
+ | 32 | warn | Set nodes have at least one field assignment in `assignments.assignments` (typeVersion 3.x) |
272
+ | 33 | warn | Schedule triggers have at least one rule in `rule.interval` |
273
+ | 34 | warn | Webhook paths are relative — no spaces, no leading slash, no protocol prefix |
257
274
 
258
275
  Errors block deployment. Warnings are recorded and fed back into the prompt for future builds.
259
276
 
@@ -392,7 +409,7 @@ try {
392
409
  |---|---|
393
410
  | `GenerationError` | Anthropic API call failed |
394
411
  | `ResponseParseError` | Claude responded but produced no usable tool call |
395
- | `ValidationError` | Workflow failed 26-rule validation after max retries (carries `.attemptMetadata` and `.warnedRules`) |
412
+ | `ValidationError` | Workflow failed 34-rule validation after max retries (carries `.attemptMetadata` and `.warnedRules`) |
396
413
  | `ProviderError` | Network/auth failure talking to n8n |
397
414
  | `ApiError` | n8n returned a 4xx or 5xx (carries `.statusCode`) |
398
415
  | `GuardError` | Input validation failed (empty description) or `delete()` called without `{ confirm: true }` |
@@ -1,16 +1,16 @@
1
1
  import {
2
2
  PromptBuilder,
3
3
  inferWorkflowType
4
- } from "./chunk-CR2NHLOH.js";
4
+ } from "./chunk-V2IZBZGB.js";
5
5
  import {
6
6
  GenerationError,
7
- GuardError,
8
7
  N8nProvider,
9
8
  NullLibrary,
10
9
  ResponseParseError,
11
10
  ValidationError
12
- } from "./chunk-6CLI43FI.js";
11
+ } from "./chunk-MYAGTDQ2.js";
13
12
  import {
13
+ GuardError,
14
14
  N8nApiClient,
15
15
  N8nFieldStripper,
16
16
  N8nValidator,
@@ -20,7 +20,7 @@ import {
20
20
  generateUUID,
21
21
  nullLogger,
22
22
  scoreToMode
23
- } from "./chunk-6IXW3WCC.js";
23
+ } from "./chunk-VPPWTMRJ.js";
24
24
 
25
25
  // src/client.ts
26
26
  import Anthropic from "@anthropic-ai/sdk";
@@ -96,7 +96,8 @@ var WorkflowDesigner = class {
96
96
  const issueLines = lastErrors.map(
97
97
  (i) => `- [Rule ${i.rule}] ${i.message}${i.nodeId ? ` (node: ${i.nodeId})` : ""}`
98
98
  );
99
- userMessage = this.promptBuilder.buildCorrectionMessage(request, matches, issueLines, attempt - 1);
99
+ const failingRuleIds = lastErrors.map((i) => i.rule);
100
+ userMessage = this.promptBuilder.buildCorrectionMessage(request, matches, issueLines, attempt - 1, failingRuleIds);
100
101
  this.logger.debug(`WorkflowDesigner: correction attempt ${attempt}`, { issueCount: lastErrors.length });
101
102
  }
102
103
  const start = Date.now();
@@ -190,11 +191,10 @@ var WorkflowDesigner = class {
190
191
  // src/client.ts
191
192
  import { homedir } from "os";
192
193
  import { join } from "path";
193
- var DEFAULT_MODEL = "claude-sonnet-4-6";
194
+ var DEFAULT_MODEL = process.env["KAIROS_MODEL"] ?? "claude-sonnet-4-6";
194
195
  var Kairos = class {
195
196
  provider;
196
197
  designer;
197
- validator;
198
198
  library;
199
199
  logger;
200
200
  telemetry;
@@ -220,7 +220,6 @@ var Kairos = class {
220
220
  const anthropic = new Anthropic({ apiKey: options.anthropicApiKey });
221
221
  const patternsPath = typeof options.telemetry === "string" ? join(options.telemetry, "..", "patterns.json") : join(homedir(), ".kairos", "patterns.json");
222
222
  this.designer = new WorkflowDesigner(anthropic, this.model, logger, patternsPath);
223
- this.validator = new N8nValidator();
224
223
  this.library = options.library ?? new NullLibrary();
225
224
  this.logger = logger;
226
225
  if (options.telemetry === true) {
@@ -317,7 +316,6 @@ var Kairos = class {
317
316
  }
318
317
  await this.emitAttemptTelemetry(description, designResult, workflowType, runId);
319
318
  const workflow = options?.name ? { ...designResult.workflow, name: options.name } : designResult.workflow;
320
- this.saveToLibrary(workflow, description, designResult, matches);
321
319
  if (options?.dryRun) {
322
320
  const totalTokensInput2 = designResult.attemptMetadata.reduce((s, m) => s + m.tokensInput, 0);
323
321
  const totalTokensOutput2 = designResult.attemptMetadata.reduce((s, m) => s + m.tokensOutput, 0);
@@ -348,10 +346,20 @@ var Kairos = class {
348
346
  }
349
347
  const provider = this.requireProvider();
350
348
  const deployed = await provider.deploy(workflow);
351
- this.recordDeploy();
349
+ this.logger.info("Workflow deployed to n8n", { workflowId: deployed.workflowId, name: deployed.name });
350
+ this.recordDeploy(deployed.workflowId);
352
351
  if (options?.activate) {
353
352
  await provider.activate(deployed.workflowId);
354
353
  }
354
+ this.saveToLibrary(workflow, description, designResult, matches, deployed.workflowId);
355
+ let smokeTestResult;
356
+ if (options?.smokeTest) {
357
+ smokeTestResult = await provider.smokeTest(deployed.workflowId, workflow).catch((err) => {
358
+ this.logger.warn("Smoke test threw unexpectedly", { err: String(err) });
359
+ return { status: "error", triggerType: "manual", error: String(err) };
360
+ });
361
+ this.logger.info("Smoke test complete", { status: smokeTestResult.status, triggerType: smokeTestResult.triggerType });
362
+ }
355
363
  const totalTokensInput = designResult.attemptMetadata.reduce((s, m) => s + m.tokensInput, 0);
356
364
  const totalTokensOutput = designResult.attemptMetadata.reduce((s, m) => s + m.tokensOutput, 0);
357
365
  await this.telemetry?.emit("build_complete", {
@@ -376,7 +384,8 @@ var Kairos = class {
376
384
  credentialsNeeded: designResult.credentialsNeeded,
377
385
  activationRequired: !options?.activate,
378
386
  generationAttempts: designResult.attempts,
379
- dryRun: false
387
+ dryRun: false,
388
+ ...smokeTestResult !== void 0 ? { smokeTest: smokeTestResult } : {}
380
389
  };
381
390
  }
382
391
  async replace(id, description) {
@@ -433,7 +442,8 @@ var Kairos = class {
433
442
  await this.emitAttemptTelemetry(description, designResult, workflowType, runId);
434
443
  const provider = this.requireProvider();
435
444
  const deployed = await provider.update(id, designResult.workflow);
436
- this.saveToLibrary(designResult.workflow, description, designResult, matches);
445
+ this.logger.info("Workflow updated in n8n", { workflowId: deployed.workflowId, name: deployed.name });
446
+ this.saveToLibrary(designResult.workflow, description, designResult, matches, deployed.workflowId);
437
447
  this.recordDeploy();
438
448
  const totalTokensInput = designResult.attemptMetadata.reduce((s, m) => s + m.tokensInput, 0);
439
449
  const totalTokensOutput = designResult.attemptMetadata.reduce((s, m) => s + m.tokensOutput, 0);
@@ -489,10 +499,10 @@ var Kairos = class {
489
499
  }, runId);
490
500
  }
491
501
  }
492
- recordDeploy() {
502
+ recordDeploy(n8nWorkflowId) {
493
503
  this.saveQueue = this.saveQueue.then(async (savedId) => {
494
504
  if (savedId) {
495
- await this.library.recordDeployment(savedId);
505
+ await this.library.recordDeployment(savedId, n8nWorkflowId);
496
506
  }
497
507
  return savedId;
498
508
  }).catch((err) => {
@@ -500,7 +510,7 @@ var Kairos = class {
500
510
  return null;
501
511
  });
502
512
  }
503
- saveToLibrary(workflow, description, designResult, matches) {
513
+ saveToLibrary(workflow, description, designResult, matches, n8nWorkflowId) {
504
514
  const failedAttempts = designResult.attemptMetadata.filter((m) => !m.validationPassed);
505
515
  const failurePatterns = failedAttempts.flatMap(
506
516
  (m) => m.issues.map((i) => ({ rule: i.rule, message: i.message }))
@@ -526,6 +536,7 @@ var Kairos = class {
526
536
  if (matches.length > 0) metadata.sourceWorkflowIds = matches.map((m) => m.workflow.id);
527
537
  if (topMatch) metadata.topMatchScore = topMatch.score;
528
538
  if (designResult.credentialsNeeded.length > 0) metadata.credentialsNeeded = designResult.credentialsNeeded;
539
+ if (n8nWorkflowId) metadata.n8nWorkflowId = n8nWorkflowId;
529
540
  const firstTryPass = designResult.attemptMetadata.length > 0 && designResult.attemptMetadata[0].validationPassed;
530
541
  const failedRules = Array.from(new Set(
531
542
  designResult.attemptMetadata.filter((m) => !m.validationPassed).flatMap((m) => m.issues.map((i) => i.rule))
@@ -586,4 +597,4 @@ var Kairos = class {
586
597
  export {
587
598
  Kairos
588
599
  };
589
- //# sourceMappingURL=chunk-4TS6GW6O.js.map
600
+ //# sourceMappingURL=chunk-GVZKMS53.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/client.ts","../src/generation/designer.ts"],"sourcesContent":["import Anthropic from '@anthropic-ai/sdk'\nimport type { N8nWorkflow, Tag } from './types/workflow.js'\nimport type { BuildResult, WorkflowListItem, ExecutionSummary, ExecutionDetail, SmokeTestResult } from './types/result.js'\nimport type { ClientOptions, BuildOptions, DeleteOptions, ExecutionFilter } from './types/options.js'\nimport type { IWorkflowLibrary, WorkflowMatch, WorkflowMetadataInput } from './library/types.js'\nimport { NullLibrary } from './library/null-library.js'\nimport { N8nApiClient } from './providers/n8n/api-client.js'\nimport { N8nFieldStripper } from './providers/n8n/stripper.js'\nimport { N8nProvider } from './providers/n8n/provider.js'\nimport { WorkflowDesigner } from './generation/designer.js'\nimport type { DesignResult } from './generation/types.js'\nimport { TelemetryCollector } from './telemetry/collector.js'\nimport { TelemetryReader } from './telemetry/reader.js'\nimport { PatternAnalyzer } from './telemetry/pattern-analyzer.js'\nimport { nullLogger } from './utils/logger.js'\nimport type { ILogger } from './utils/logger.js'\nimport { scoreToMode } from './utils/thresholds.js'\nimport { GuardError } from './errors/guard-error.js'\nimport { ValidationError } from './errors/validation-error.js'\nimport { inferWorkflowType } from './utils/workflow-type.js'\nimport { generateUUID } from './utils/uuid.js'\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\n\nconst DEFAULT_MODEL = process.env['KAIROS_MODEL'] ?? 'claude-sonnet-4-6'\n\nexport class Kairos {\n private readonly provider: N8nProvider | null\n private readonly designer: WorkflowDesigner\n private readonly library: IWorkflowLibrary\n private readonly logger: ILogger\n private readonly telemetry: TelemetryCollector | null\n private readonly telemetryReader: TelemetryReader | null\n private readonly patternAnalyzer: PatternAnalyzer | null\n private readonly model: string\n private saveQueue: Promise<string | null> = Promise.resolve(null)\n\n constructor(options: ClientOptions) {\n const logger = options.logger ?? nullLogger\n this.model = options.model ?? DEFAULT_MODEL\n\n if (options.n8nBaseUrl && options.n8nApiKey) {\n try {\n new URL(options.n8nBaseUrl)\n } catch {\n throw new GuardError(`Invalid n8nBaseUrl: \"${options.n8nBaseUrl}\" — must be a valid URL`)\n }\n const apiClient = new N8nApiClient(options.n8nBaseUrl, options.n8nApiKey, logger)\n const stripper = new N8nFieldStripper()\n this.provider = new N8nProvider(apiClient, stripper)\n } else {\n this.provider = null\n }\n\n const anthropic = new Anthropic({ apiKey: options.anthropicApiKey })\n const patternsPath = typeof options.telemetry === 'string'\n ? join(options.telemetry, '..', 'patterns.json')\n : join(homedir(), '.kairos', 'patterns.json')\n this.designer = new WorkflowDesigner(anthropic, this.model, logger, patternsPath)\n this.library = options.library ?? new NullLibrary()\n this.logger = logger\n\n if (options.telemetry === true) {\n this.telemetry = new TelemetryCollector()\n this.telemetryReader = new TelemetryReader()\n this.patternAnalyzer = new PatternAnalyzer()\n } else if (typeof options.telemetry === 'string') {\n this.telemetry = new TelemetryCollector(options.telemetry)\n this.telemetryReader = new TelemetryReader(options.telemetry)\n this.patternAnalyzer = new PatternAnalyzer(options.telemetry)\n } else {\n this.telemetry = null\n this.telemetryReader = null\n this.patternAnalyzer = null\n }\n }\n\n private requireProvider(): N8nProvider {\n if (!this.provider) {\n throw new GuardError('n8nBaseUrl and n8nApiKey are required for this operation — set them in the Kairos constructor, or use { dryRun: true } for generation-only mode')\n }\n return this.provider\n }\n\n private validateDescription(description: string): void {\n if (!description || description.trim().length === 0) {\n throw new GuardError('Description is required and must be non-empty')\n }\n }\n\n async build(description: string, options?: BuildOptions): Promise<BuildResult> {\n this.validateDescription(description)\n this.logger.info('Kairos.build', { description, dryRun: options?.dryRun })\n const buildStart = Date.now()\n const runId = generateUUID()\n const workflowType = inferWorkflowType(description)\n\n await this.telemetry?.emit('build_start', {\n description,\n model: this.model,\n dryRun: options?.dryRun ?? false,\n }, runId)\n\n await this.library.initialize()\n const matches = await this.library.search(description)\n\n if (matches.length > 0) {\n const top = matches[0]!\n this.logger.info(`Library: ${matches.length} match(es), top=\"${top.workflow.description.slice(0, 50)}\" score=${top.score.toFixed(2)} mode=${top.mode}`)\n } else {\n this.logger.info('Library: no matches (scratch mode)')\n }\n\n const globalFailureRates = await this.telemetryReader?.getFailureRates() ?? []\n\n if (globalFailureRates.length > 0) {\n const highFreq = globalFailureRates.filter((r) => r.rate >= 0.15)\n if (highFreq.length > 0) {\n this.logger.info(`Telemetry: ${highFreq.length} high-frequency failure rule(s) will be warned about`)\n }\n }\n\n let designResult: DesignResult\n try {\n designResult = await this.designer.design(\n { description, ...(options?.name ? { name: options.name } : {}) },\n matches,\n globalFailureRates,\n )\n } catch (err) {\n if (err instanceof ValidationError && err.attemptMetadata) {\n for (const meta of err.attemptMetadata) {\n await this.telemetry?.emit('generation_attempt', {\n description,\n attempt: meta.attempt,\n temperature: meta.temperature,\n durationMs: meta.durationMs,\n tokensInput: meta.tokensInput,\n tokensOutput: meta.tokensOutput,\n validationPassed: meta.validationPassed,\n issueCount: meta.issues.length,\n issues: meta.issues.map((i) => ({ rule: i.rule, severity: i.severity, message: i.message, nodeId: i.nodeId ?? null, nodeType: i.nodeType ?? null })),\n workflowType,\n }, runId)\n }\n await this.telemetry?.emit('build_complete', {\n description,\n success: false,\n totalAttempts: err.attemptMetadata.length,\n totalDurationMs: Date.now() - buildStart,\n totalTokensInput: err.attemptMetadata.reduce((s, m) => s + m.tokensInput, 0),\n totalTokensOutput: err.attemptMetadata.reduce((s, m) => s + m.tokensOutput, 0),\n workflowName: null,\n workflowId: null,\n dryRun: options?.dryRun ?? false,\n credentialsNeeded: 0,\n warnedRules: err.warnedRules ?? [],\n workflowType,\n }, runId)\n this.updatePatterns()\n }\n throw err\n }\n\n await this.emitAttemptTelemetry(description, designResult, workflowType, runId)\n\n const workflow = options?.name\n ? { ...designResult.workflow, name: options.name }\n : designResult.workflow\n\n if (options?.dryRun) {\n const totalTokensInput = designResult.attemptMetadata.reduce((s, m) => s + m.tokensInput, 0)\n const totalTokensOutput = designResult.attemptMetadata.reduce((s, m) => s + m.tokensOutput, 0)\n\n await this.telemetry?.emit('build_complete', {\n description,\n success: true,\n totalAttempts: designResult.attempts,\n totalDurationMs: Date.now() - buildStart,\n totalTokensInput,\n totalTokensOutput,\n workflowName: workflow.name,\n workflowId: null,\n dryRun: true,\n credentialsNeeded: designResult.credentialsNeeded.length,\n warnedRules: designResult.warnedRules,\n workflowType,\n }, runId)\n\n this.updatePatterns()\n\n return {\n workflowId: null,\n name: workflow.name,\n workflow,\n credentialsNeeded: designResult.credentialsNeeded,\n activationRequired: true,\n generationAttempts: designResult.attempts,\n dryRun: true,\n }\n }\n\n const provider = this.requireProvider()\n const deployed = await provider.deploy(workflow)\n // Log the workflow ID immediately — if any post-deploy step fails, this ID\n // lets the user manually locate and clean up the orphaned workflow in n8n.\n this.logger.info('Workflow deployed to n8n', { workflowId: deployed.workflowId, name: deployed.name })\n this.recordDeploy(deployed.workflowId)\n\n if (options?.activate) {\n await provider.activate(deployed.workflowId)\n }\n\n this.saveToLibrary(workflow, description, designResult, matches, deployed.workflowId)\n\n let smokeTestResult: SmokeTestResult | undefined\n if (options?.smokeTest) {\n smokeTestResult = await provider.smokeTest(deployed.workflowId, workflow).catch((err: unknown): SmokeTestResult => {\n this.logger.warn('Smoke test threw unexpectedly', { err: String(err) })\n return { status: 'error', triggerType: 'manual', error: String(err) }\n })\n this.logger.info('Smoke test complete', { status: smokeTestResult.status, triggerType: smokeTestResult.triggerType })\n }\n\n const totalTokensInput = designResult.attemptMetadata.reduce((s, m) => s + m.tokensInput, 0)\n const totalTokensOutput = designResult.attemptMetadata.reduce((s, m) => s + m.tokensOutput, 0)\n\n await this.telemetry?.emit('build_complete', {\n description,\n success: true,\n totalAttempts: designResult.attempts,\n totalDurationMs: Date.now() - buildStart,\n totalTokensInput,\n totalTokensOutput,\n workflowName: deployed.name,\n workflowId: deployed.workflowId,\n dryRun: false,\n credentialsNeeded: designResult.credentialsNeeded.length,\n warnedRules: designResult.warnedRules,\n workflowType,\n }, runId)\n\n this.updatePatterns()\n\n return {\n workflowId: deployed.workflowId,\n name: deployed.name,\n workflow,\n credentialsNeeded: designResult.credentialsNeeded,\n activationRequired: !options?.activate,\n generationAttempts: designResult.attempts,\n dryRun: false,\n ...(smokeTestResult !== undefined ? { smokeTest: smokeTestResult } : {}),\n }\n }\n\n async replace(id: string, description: string): Promise<BuildResult> {\n this.validateDescription(description)\n this.logger.info('Kairos.update', { id, description })\n const buildStart = Date.now()\n const runId = generateUUID()\n const workflowType = inferWorkflowType(description)\n\n await this.telemetry?.emit('build_start', {\n description,\n model: this.model,\n dryRun: false,\n }, runId)\n\n await this.library.initialize()\n const matches = await this.library.search(description)\n const globalFailureRates = await this.telemetryReader?.getFailureRates() ?? []\n\n let designResult: DesignResult\n try {\n designResult = await this.designer.design({ description }, matches, globalFailureRates)\n } catch (err) {\n if (err instanceof ValidationError && err.attemptMetadata) {\n for (const meta of err.attemptMetadata) {\n await this.telemetry?.emit('generation_attempt', {\n description,\n attempt: meta.attempt,\n temperature: meta.temperature,\n durationMs: meta.durationMs,\n tokensInput: meta.tokensInput,\n tokensOutput: meta.tokensOutput,\n validationPassed: meta.validationPassed,\n issueCount: meta.issues.length,\n issues: meta.issues.map((i) => ({ rule: i.rule, severity: i.severity, message: i.message, nodeId: i.nodeId ?? null, nodeType: i.nodeType ?? null })),\n workflowType,\n }, runId)\n }\n await this.telemetry?.emit('build_complete', {\n description,\n success: false,\n totalAttempts: err.attemptMetadata.length,\n totalDurationMs: Date.now() - buildStart,\n totalTokensInput: err.attemptMetadata.reduce((s, m) => s + m.tokensInput, 0),\n totalTokensOutput: err.attemptMetadata.reduce((s, m) => s + m.tokensOutput, 0),\n workflowName: null,\n workflowId: null,\n dryRun: false,\n credentialsNeeded: 0,\n warnedRules: err.warnedRules ?? [],\n workflowType,\n }, runId)\n this.updatePatterns()\n }\n throw err\n }\n\n await this.emitAttemptTelemetry(description, designResult, workflowType, runId)\n\n const provider = this.requireProvider()\n const deployed = await provider.update(id, designResult.workflow)\n this.logger.info('Workflow updated in n8n', { workflowId: deployed.workflowId, name: deployed.name })\n\n this.saveToLibrary(designResult.workflow, description, designResult, matches, deployed.workflowId)\n this.recordDeploy()\n\n const totalTokensInput = designResult.attemptMetadata.reduce((s, m) => s + m.tokensInput, 0)\n const totalTokensOutput = designResult.attemptMetadata.reduce((s, m) => s + m.tokensOutput, 0)\n\n await this.telemetry?.emit('build_complete', {\n description,\n success: true,\n totalAttempts: designResult.attempts,\n totalDurationMs: Date.now() - buildStart,\n totalTokensInput,\n totalTokensOutput,\n workflowName: deployed.name,\n workflowId: deployed.workflowId,\n dryRun: false,\n credentialsNeeded: designResult.credentialsNeeded.length,\n warnedRules: designResult.warnedRules,\n workflowType,\n }, runId)\n\n this.updatePatterns()\n\n return {\n workflowId: deployed.workflowId,\n name: deployed.name,\n workflow: designResult.workflow,\n credentialsNeeded: designResult.credentialsNeeded,\n activationRequired: true,\n generationAttempts: designResult.attempts,\n dryRun: false,\n }\n }\n\n async drain(): Promise<void> {\n await this.saveQueue.catch(() => {})\n }\n\n private updatePatterns(): void {\n if (!this.patternAnalyzer) return\n this.saveQueue = this.saveQueue\n .then(() => this.patternAnalyzer!.analyzeAndSave())\n .then(() => null)\n .catch((err: unknown) => {\n this.logger.warn('Pattern analysis failed (non-fatal)', { err: String(err) })\n return null\n })\n }\n\n private async emitAttemptTelemetry(description: string, designResult: DesignResult, workflowType: string | null, runId: string): Promise<void> {\n for (const meta of designResult.attemptMetadata) {\n await this.telemetry?.emit('generation_attempt', {\n description,\n attempt: meta.attempt,\n temperature: meta.temperature,\n durationMs: meta.durationMs,\n tokensInput: meta.tokensInput,\n tokensOutput: meta.tokensOutput,\n validationPassed: meta.validationPassed,\n issueCount: meta.issues.length,\n issues: meta.issues.map((i) => ({ rule: i.rule, severity: i.severity, message: i.message, nodeId: i.nodeId ?? null, nodeType: i.nodeType ?? null })),\n workflowType,\n }, runId)\n }\n }\n\n private recordDeploy(n8nWorkflowId?: string): void {\n this.saveQueue = this.saveQueue\n .then(async (savedId) => {\n if (savedId) {\n await this.library.recordDeployment(savedId, n8nWorkflowId)\n }\n return savedId\n })\n .catch((err: unknown) => {\n this.logger.warn('Failed to record deployment (non-fatal)', { err: String(err) })\n return null\n })\n }\n\n private saveToLibrary(\n workflow: N8nWorkflow,\n description: string,\n designResult: DesignResult,\n matches: WorkflowMatch[],\n n8nWorkflowId?: string,\n ): void {\n const failedAttempts = designResult.attemptMetadata.filter((m) => !m.validationPassed)\n const failurePatterns = failedAttempts.flatMap((m) =>\n m.issues.map((i) => ({ rule: i.rule, message: i.message })),\n )\n const topMatch = matches[0]\n const generationMode = topMatch ? scoreToMode(topMatch.score) : 'scratch' as const\n\n const autoTags = Array.from(new Set(\n workflow.nodes.flatMap((n) => {\n const bare = n.type.split('.').pop() ?? ''\n const tags = [bare]\n if (n.type.includes('Trigger') || n.type.includes('trigger')) tags.push(`trigger:${bare}`)\n if (n.type.includes('langchain')) tags.push('ai')\n return tags\n }),\n ))\n\n const metadata: WorkflowMetadataInput = {\n description,\n generationMode,\n generationAttempts: designResult.attempts,\n }\n if (autoTags.length > 0) metadata.tags = autoTags\n if (failurePatterns.length > 0) metadata.failurePatterns = failurePatterns\n if (matches.length > 0) metadata.sourceWorkflowIds = matches.map((m) => m.workflow.id)\n if (topMatch) metadata.topMatchScore = topMatch.score\n if (designResult.credentialsNeeded.length > 0) metadata.credentialsNeeded = designResult.credentialsNeeded\n if (n8nWorkflowId) metadata.n8nWorkflowId = n8nWorkflowId\n\n const firstTryPass = designResult.attemptMetadata.length > 0\n && designResult.attemptMetadata[0]!.validationPassed\n const failedRules = Array.from(new Set(\n designResult.attemptMetadata\n .filter((m) => !m.validationPassed)\n .flatMap((m) => m.issues.map((i) => i.rule)),\n ))\n\n this.saveQueue = this.saveQueue\n .then(async () => {\n const savedId = await this.library.save(workflow, metadata)\n\n for (const match of matches) {\n if (match.mode === 'direct' || match.mode === 'reference') {\n await this.library.recordOutcome(match.workflow.id, {\n attempts: designResult.attempts,\n firstTryPass,\n failedRules,\n mode: match.mode,\n })\n }\n }\n\n return savedId\n })\n .catch((err: unknown) => {\n this.logger.warn('Failed to save workflow to library (non-fatal)', { err: String(err) })\n return null\n })\n }\n\n async get(id: string): Promise<N8nWorkflow> {\n return this.requireProvider().get(id)\n }\n\n async list(): Promise<WorkflowListItem[]> {\n return this.requireProvider().list()\n }\n\n async activate(id: string): Promise<void> {\n await this.requireProvider().activate(id)\n }\n\n async deactivate(id: string): Promise<void> {\n await this.requireProvider().deactivate(id)\n }\n\n async delete(id: string, options: DeleteOptions): Promise<void> {\n await this.requireProvider().delete(id, options)\n }\n\n async executions(workflowId?: string, filter?: ExecutionFilter): Promise<ExecutionSummary[]> {\n return this.requireProvider().executions(workflowId, filter)\n }\n\n async execution(id: string): Promise<ExecutionDetail> {\n return this.requireProvider().execution(id)\n }\n\n async listTags(): Promise<Tag[]> {\n return this.requireProvider().listTags()\n }\n\n async createTag(name: string): Promise<Tag> {\n return this.requireProvider().createTag(name)\n }\n\n async tag(workflowId: string, tagIds: string[]): Promise<void> {\n await this.requireProvider().tag(workflowId, tagIds)\n }\n\n async untag(workflowId: string, tagIds: string[]): Promise<void> {\n await this.requireProvider().untag(workflowId, tagIds)\n }\n}\n","import Anthropic from '@anthropic-ai/sdk'\nimport type { WorkflowMatch } from '../library/types.js'\nimport type { N8nWorkflow } from '../types/workflow.js'\nimport type { CredentialRequirement } from '../types/result.js'\nimport type { ILogger } from '../utils/logger.js'\nimport { GenerationError } from '../errors/generation-error.js'\nimport { ResponseParseError } from '../errors/response-parse-error.js'\nimport { ValidationError } from '../errors/validation-error.js'\nimport type { ValidationIssue } from '../errors/validation-error.js'\nimport { N8nValidator } from '../validation/validator.js'\nimport { PromptBuilder } from './prompt-builder.js'\nimport type { AttemptMetadata } from '../telemetry/types.js'\nimport type { RuleFailureRate } from '../telemetry/reader.js'\nimport type { DesignRequest, DesignResult, SystemPromptBlock } from './types.js'\n\nconst MAX_ATTEMPTS = 3\nconst BASE_TEMPERATURE = 0.2\nconst FINAL_TEMPERATURE = 0.1\n\nconst GENERATE_WORKFLOW_TOOL: Anthropic.Tool = {\n name: 'generate_workflow',\n description: 'Generate a valid n8n workflow JSON object',\n input_schema: {\n type: 'object',\n properties: {\n workflow: {\n type: 'object',\n description: 'The complete n8n workflow object',\n properties: {\n name: { type: 'string' },\n nodes: { type: 'array' },\n connections: { type: 'object' },\n settings: { type: 'object' },\n },\n required: ['name', 'nodes', 'connections'],\n },\n credentialsNeeded: {\n type: 'array',\n description: 'List of credentials the user must configure before activating',\n items: {\n type: 'object',\n properties: {\n service: { type: 'string' },\n credentialType: { type: 'string' },\n description: { type: 'string' },\n },\n required: ['service', 'credentialType', 'description'],\n },\n },\n error: {\n type: 'string',\n description: 'Set this if the request cannot be fulfilled — explain why',\n },\n },\n required: [],\n },\n}\n\ninterface ToolUseResult {\n workflow: N8nWorkflow\n credentialsNeeded: CredentialRequirement[]\n error?: string\n}\n\nexport class WorkflowDesigner {\n private readonly validator: N8nValidator\n private readonly promptBuilder: PromptBuilder\n\n constructor(\n private readonly anthropic: Anthropic,\n private readonly model: string,\n private readonly logger: ILogger,\n patternsPath?: string,\n ) {\n this.validator = new N8nValidator()\n this.promptBuilder = new PromptBuilder(patternsPath)\n }\n\n async design(request: DesignRequest, matches: WorkflowMatch[], globalFailureRates: RuleFailureRate[] = []): Promise<DesignResult> {\n const attemptMetadata: AttemptMetadata[] = []\n let lastErrors: ValidationIssue[] = []\n let attempts = 0\n const built = this.promptBuilder.build(request, matches, globalFailureRates)\n\n for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) {\n attempts = attempt\n const temperature = attempt === MAX_ATTEMPTS ? FINAL_TEMPERATURE : BASE_TEMPERATURE\n\n let userMessage: string\n if (attempt === 1) {\n userMessage = built.userMessage\n this.logger.debug('WorkflowDesigner: attempt 1', { description: request.description })\n } else {\n const issueLines = lastErrors.map(\n (i) => `- [Rule ${i.rule}] ${i.message}${i.nodeId ? ` (node: ${i.nodeId})` : ''}`,\n )\n const failingRuleIds = lastErrors.map((i) => i.rule)\n userMessage = this.promptBuilder.buildCorrectionMessage(request, matches, issueLines, attempt - 1, failingRuleIds)\n this.logger.debug(`WorkflowDesigner: correction attempt ${attempt}`, { issueCount: lastErrors.length })\n }\n\n const start = Date.now()\n const message = await this.callClaude(built.system, userMessage, temperature)\n const durationMs = Date.now() - start\n const parsed = this.extractToolUse(message)\n\n if (parsed.error) {\n throw new GenerationError(`Claude declined to generate workflow: ${parsed.error}`)\n }\n\n const validation = this.validator.validate(parsed.workflow)\n const errors = validation.issues.filter((i) => i.severity === 'error')\n\n attemptMetadata.push({\n attempt,\n temperature,\n durationMs,\n tokensInput: message.usage.input_tokens,\n tokensOutput: message.usage.output_tokens,\n validationPassed: validation.valid,\n issues: validation.issues,\n })\n\n if (validation.valid) {\n return { workflow: parsed.workflow, credentialsNeeded: parsed.credentialsNeeded, attempts, attemptMetadata, warnedRules: this.promptBuilder.getWarnedRules() }\n }\n\n lastErrors = errors\n this.logger.warn(`WorkflowDesigner: validation failed on attempt ${attempt}`, {\n errorCount: errors.length,\n })\n }\n\n const finalIssues = attemptMetadata.at(-1)?.issues ?? lastErrors\n throw new ValidationError(\n `Workflow failed validation after ${MAX_ATTEMPTS} attempts`,\n finalIssues,\n attemptMetadata,\n this.promptBuilder.getWarnedRules(),\n )\n }\n\n private async callClaude(\n system: SystemPromptBlock[],\n userMessage: string,\n temperature: number,\n ): Promise<Anthropic.Message> {\n const controller = new AbortController()\n const timer = setTimeout(() => controller.abort(), 120_000)\n try {\n return await this.anthropic.messages.create(\n {\n model: this.model,\n max_tokens: 8192,\n temperature,\n system: system.map((b) => ({ type: b.type, text: b.text, ...(b.cache_control ? { cache_control: b.cache_control } : {}) })),\n messages: [{ role: 'user', content: userMessage }],\n tools: [GENERATE_WORKFLOW_TOOL],\n tool_choice: { type: 'tool', name: 'generate_workflow' },\n },\n { signal: controller.signal },\n )\n } catch (err) {\n const detail = err instanceof Error ? err.message : String(err)\n throw new GenerationError(`Anthropic API call failed: ${detail}`, err)\n } finally {\n clearTimeout(timer)\n }\n }\n\n private extractToolUse(message: Anthropic.Message): ToolUseResult {\n if (message.stop_reason === 'max_tokens') {\n throw new GenerationError(\n 'Claude response was truncated (max_tokens reached) — the workflow may be too large. Try a simpler description or break it into smaller workflows.',\n )\n }\n\n const toolUseBlock = message.content.find(\n (block): block is Anthropic.ToolUseBlock => block.type === 'tool_use',\n )\n if (!toolUseBlock) {\n throw new ResponseParseError(\n 'Claude response contained no tool_use block — forced tool_choice failed unexpectedly',\n )\n }\n\n const input = toolUseBlock.input as Record<string, unknown>\n\n if (typeof input['error'] === 'string') {\n return {\n workflow: { name: '', nodes: [], connections: {} },\n credentialsNeeded: [],\n error: input['error'],\n }\n }\n\n if (!input['workflow'] || typeof input['workflow'] !== 'object') {\n throw new ResponseParseError('generate_workflow tool call missing workflow field')\n }\n\n const workflow = input['workflow'] as N8nWorkflow\n const credentialsNeeded = (input['credentialsNeeded'] as CredentialRequirement[] | undefined) ?? []\n\n return { workflow, credentialsNeeded }\n }\n}\n"],"mappings":"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","names":["totalTokensInput","totalTokensOutput"]}
@@ -1,8 +1,10 @@
1
1
  import {
2
+ GuardError,
2
3
  KairosError,
3
4
  N8nValidator,
5
+ ProviderError,
4
6
  generateUUID
5
- } from "./chunk-6IXW3WCC.js";
7
+ } from "./chunk-VPPWTMRJ.js";
6
8
 
7
9
  // src/library/null-library.ts
8
10
  var NullLibrary = class {
@@ -26,15 +28,9 @@ var NullLibrary = class {
26
28
  }
27
29
  };
28
30
 
29
- // src/errors/guard-error.ts
30
- var GuardError = class extends KairosError {
31
- constructor(message) {
32
- super(message);
33
- this.name = "GuardError";
34
- }
35
- };
36
-
37
31
  // src/providers/n8n/provider.ts
32
+ var SMOKE_TEST_TIMEOUT_MS = 3e4;
33
+ var SMOKE_TEST_POLL_INTERVAL_MS = 1e3;
38
34
  var N8nProvider = class {
39
35
  constructor(client, stripper) {
40
36
  this.client = client;
@@ -96,6 +92,71 @@ var N8nProvider = class {
96
92
  async untag(workflowId, tagIds) {
97
93
  await this.client.untagWorkflow(workflowId, tagIds);
98
94
  }
95
+ async smokeTest(workflowId, workflow) {
96
+ const start = Date.now();
97
+ const trigger = this.detectTrigger(workflow);
98
+ if (trigger.type === "unsupported") {
99
+ return { status: "not-applicable", triggerType: "not-applicable" };
100
+ }
101
+ if (trigger.type === "manual") {
102
+ let executionId;
103
+ try {
104
+ executionId = await this.client.triggerManual(workflowId);
105
+ } catch (err) {
106
+ return { status: "error", triggerType: "manual", durationMs: Date.now() - start, error: String(err) };
107
+ }
108
+ try {
109
+ const execution = await this.pollExecution(executionId);
110
+ const durationMs = Date.now() - start;
111
+ if (execution.status === "success") {
112
+ return { status: "passed", triggerType: "manual", executionId, durationMs };
113
+ }
114
+ return {
115
+ status: "failed",
116
+ triggerType: "manual",
117
+ executionId,
118
+ durationMs,
119
+ error: `Execution ended with status: ${execution.status}`
120
+ };
121
+ } catch (err) {
122
+ return { status: "error", triggerType: "manual", executionId, durationMs: Date.now() - start, error: String(err) };
123
+ }
124
+ }
125
+ try {
126
+ const statusCode = await this.client.triggerWebhookTest(trigger.path);
127
+ const durationMs = Date.now() - start;
128
+ if (statusCode >= 200 && statusCode < 300) {
129
+ return { status: "passed", triggerType: "webhook", durationMs };
130
+ }
131
+ return { status: "failed", triggerType: "webhook", durationMs, error: `Webhook returned HTTP ${statusCode}` };
132
+ } catch (err) {
133
+ return { status: "error", triggerType: "webhook", durationMs: Date.now() - start, error: String(err) };
134
+ }
135
+ }
136
+ detectTrigger(workflow) {
137
+ for (const node of workflow.nodes) {
138
+ if (node.type === "n8n-nodes-base.manualTrigger") return { type: "manual" };
139
+ if (node.type === "n8n-nodes-base.webhook") {
140
+ const params = node.parameters;
141
+ const path = typeof params?.["path"] === "string" ? params["path"] : "webhook";
142
+ return { type: "webhook", path };
143
+ }
144
+ }
145
+ return { type: "unsupported" };
146
+ }
147
+ async pollExecution(executionId) {
148
+ const deadline = Date.now() + SMOKE_TEST_TIMEOUT_MS;
149
+ for (; ; ) {
150
+ const execution = await this.client.getExecution(executionId);
151
+ if (execution.status !== "running" && execution.status !== "waiting") {
152
+ return execution;
153
+ }
154
+ const remaining = deadline - Date.now();
155
+ if (remaining <= 0) break;
156
+ await new Promise((resolve) => setTimeout(resolve, Math.min(SMOKE_TEST_POLL_INTERVAL_MS, remaining)));
157
+ }
158
+ throw new ProviderError(`Smoke test: execution ${executionId} did not complete within ${SMOKE_TEST_TIMEOUT_MS}ms`);
159
+ }
99
160
  };
100
161
 
101
162
  // src/errors/generation-error.ts
@@ -144,6 +205,19 @@ var SECRET_PATTERNS = [
144
205
  /AIza[a-zA-Z0-9_-]{35}/,
145
206
  /AKIA[A-Z0-9]{16}/
146
207
  ];
208
+ var SECRET_PREFIXES = ["sk-", "ghp_", "xoxb-", "AIza", "AKIA"];
209
+ function collectExpressionStrings(obj, out = []) {
210
+ if (typeof obj === "string") {
211
+ if (obj.includes("={{")) out.push(obj);
212
+ } else if (Array.isArray(obj)) {
213
+ for (const item of obj) collectExpressionStrings(item, out);
214
+ } else if (obj !== null && typeof obj === "object") {
215
+ for (const val of Object.values(obj)) {
216
+ collectExpressionStrings(val, out);
217
+ }
218
+ }
219
+ return out;
220
+ }
147
221
  function assessTemplateSafety(workflow) {
148
222
  const reasons = [];
149
223
  let worst = "safe";
@@ -166,6 +240,15 @@ function assessTemplateSafety(workflow) {
166
240
  break;
167
241
  }
168
242
  }
243
+ const expressions = collectExpressionStrings(node.parameters);
244
+ for (const expr of expressions) {
245
+ for (const prefix of SECRET_PREFIXES) {
246
+ if (expr.includes(prefix)) {
247
+ escalate("review", `Node "${node.name}" has an expression containing credential-like prefix "${prefix}"`);
248
+ break;
249
+ }
250
+ }
251
+ }
169
252
  }
170
253
  return { trustLevel: worst, reasons };
171
254
  }
@@ -223,12 +306,26 @@ var TemplateSyncer = class {
223
306
  }
224
307
  return progress;
225
308
  }
309
+ async fetchWithBackoff(url, maxRetries = 3) {
310
+ let delayMs = DELAY_BETWEEN_FETCHES_MS;
311
+ let lastResponse;
312
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
313
+ lastResponse = await fetch(url);
314
+ if (lastResponse.status !== 429 && lastResponse.status !== 503) return lastResponse;
315
+ if (attempt === maxRetries) break;
316
+ const retryAfterHeader = lastResponse.headers.get("Retry-After");
317
+ const waitMs = retryAfterHeader ? parseInt(retryAfterHeader, 10) * 1e3 : delayMs * Math.pow(2, attempt);
318
+ this.logger.warn(`HTTP ${lastResponse.status} from template API, retrying in ${waitMs}ms`, { url, attempt });
319
+ await new Promise((resolve) => setTimeout(resolve, waitMs));
320
+ }
321
+ return lastResponse;
322
+ }
226
323
  async fetchTemplateIds(max, progress) {
227
324
  const ids = [];
228
325
  let page = 1;
229
326
  while (ids.length < max) {
230
327
  const url = `${N8N_TEMPLATE_API}/search?page=${page}&rows=${PAGE_SIZE}`;
231
- const response = await fetch(url);
328
+ const response = await this.fetchWithBackoff(url);
232
329
  if (!response.ok) break;
233
330
  const data = await response.json();
234
331
  progress.total = Math.min(data.totalWorkflows, max);
@@ -248,7 +345,7 @@ var TemplateSyncer = class {
248
345
  }
249
346
  async processTemplate(id, progress) {
250
347
  const url = `${N8N_TEMPLATE_API}/workflows/${id}`;
251
- const response = await fetch(url);
348
+ const response = await this.fetchWithBackoff(url);
252
349
  if (!response.ok) return;
253
350
  const data = await response.json();
254
351
  const templateMeta = data.workflow;
@@ -305,11 +402,10 @@ var TemplateSyncer = class {
305
402
 
306
403
  export {
307
404
  NullLibrary,
308
- GuardError,
309
405
  N8nProvider,
310
406
  GenerationError,
311
407
  ResponseParseError,
312
408
  ValidationError,
313
409
  TemplateSyncer
314
410
  };
315
- //# sourceMappingURL=chunk-6CLI43FI.js.map
411
+ //# sourceMappingURL=chunk-MYAGTDQ2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/library/null-library.ts","../src/providers/n8n/provider.ts","../src/errors/generation-error.ts","../src/errors/response-parse-error.ts","../src/errors/validation-error.ts","../src/templates/safety.ts","../src/templates/syncer.ts"],"sourcesContent":["import type { IWorkflowLibrary, WorkflowMatch, StoredWorkflow, WorkflowMetadataInput, LibraryFilters, SearchOptions, OutcomeData } from './types.js'\nimport type { N8nWorkflow } from '../types/workflow.js'\nimport { generateUUID } from '../utils/uuid.js'\n\nexport class NullLibrary implements IWorkflowLibrary {\n async initialize(): Promise<void> {}\n\n async search(_description: string, _options?: SearchOptions): Promise<WorkflowMatch[]> {\n return []\n }\n\n async save(_workflow: N8nWorkflow, _metadata: WorkflowMetadataInput): Promise<string> {\n return generateUUID()\n }\n\n async recordDeployment(_id: string): Promise<void> {}\n\n async recordOutcome(_id: string, _outcome: OutcomeData): Promise<void> {}\n\n async get(_id: string): Promise<StoredWorkflow | null> {\n return null\n }\n\n async list(_filters?: LibraryFilters): Promise<StoredWorkflow[]> {\n return []\n }\n}\n","import type { N8nWorkflow, Tag } from '../../types/workflow.js'\nimport type { DeployResult, WorkflowListItem, ExecutionSummary, ExecutionDetail, SmokeTestResult } from '../../types/result.js'\nimport type { DeleteOptions, ExecutionFilter } from '../../types/options.js'\nimport type { IProvider } from '../types.js'\nimport { GuardError } from '../../errors/guard-error.js'\nimport { ProviderError } from '../../errors/provider-error.js'\nimport { N8nApiClient } from './api-client.js'\nimport { N8nFieldStripper } from './stripper.js'\n\nconst SMOKE_TEST_TIMEOUT_MS = 30_000\nconst SMOKE_TEST_POLL_INTERVAL_MS = 1_000\n\ntype TriggerInfo =\n | { type: 'manual' }\n | { type: 'webhook'; path: string }\n | { type: 'unsupported' }\n\nexport class N8nProvider implements IProvider {\n readonly platform = 'n8n'\n\n constructor(\n private readonly client: N8nApiClient,\n private readonly stripper: N8nFieldStripper,\n ) {}\n\n async deploy(workflow: N8nWorkflow): Promise<DeployResult> {\n const stripped = this.stripper.stripForCreate(workflow)\n const response = await this.client.createWorkflow(stripped)\n return { workflowId: response.id, name: response.name }\n }\n\n async update(id: string, workflow: N8nWorkflow): Promise<DeployResult> {\n const stripped = this.stripper.stripForUpdate(workflow)\n const response = await this.client.updateWorkflow(id, stripped)\n return { workflowId: response.id, name: response.name }\n }\n\n async get(id: string): Promise<N8nWorkflow> {\n const response = await this.client.getWorkflow(id)\n return {\n name: response.name,\n nodes: response.nodes,\n connections: response.connections,\n ...(response.settings !== undefined ? { settings: response.settings } : {}),\n ...(response.tags !== undefined ? { tags: response.tags } : {}),\n }\n }\n\n async list(): Promise<WorkflowListItem[]> {\n return this.client.listWorkflows()\n }\n\n async activate(id: string): Promise<void> {\n await this.client.activateWorkflow(id)\n }\n\n async deactivate(id: string): Promise<void> {\n await this.client.deactivateWorkflow(id)\n }\n\n async delete(id: string, options: DeleteOptions): Promise<void> {\n if (options.confirm !== true) {\n throw new GuardError('delete() requires { confirm: true } to prevent accidental deletion')\n }\n await this.client.deleteWorkflow(id)\n }\n\n async executions(workflowId?: string, filter?: ExecutionFilter): Promise<ExecutionSummary[]> {\n return this.client.getExecutions(workflowId, filter)\n }\n\n async execution(id: string): Promise<ExecutionDetail> {\n return this.client.getExecution(id)\n }\n\n async listTags(): Promise<Tag[]> {\n return this.client.listTags()\n }\n\n async createTag(name: string): Promise<Tag> {\n return this.client.createTag(name)\n }\n\n async tag(workflowId: string, tagIds: string[]): Promise<void> {\n await this.client.tagWorkflow(workflowId, tagIds)\n }\n\n async untag(workflowId: string, tagIds: string[]): Promise<void> {\n await this.client.untagWorkflow(workflowId, tagIds)\n }\n\n async smokeTest(workflowId: string, workflow: N8nWorkflow): Promise<SmokeTestResult> {\n const start = Date.now()\n const trigger = this.detectTrigger(workflow)\n\n if (trigger.type === 'unsupported') {\n return { status: 'not-applicable', triggerType: 'not-applicable' }\n }\n\n if (trigger.type === 'manual') {\n let executionId: string\n try {\n executionId = await this.client.triggerManual(workflowId)\n } catch (err) {\n return { status: 'error', triggerType: 'manual', durationMs: Date.now() - start, error: String(err) }\n }\n try {\n const execution = await this.pollExecution(executionId)\n const durationMs = Date.now() - start\n if (execution.status === 'success') {\n return { status: 'passed', triggerType: 'manual', executionId, durationMs }\n }\n return {\n status: 'failed',\n triggerType: 'manual',\n executionId,\n durationMs,\n error: `Execution ended with status: ${execution.status}`,\n }\n } catch (err) {\n return { status: 'error', triggerType: 'manual', executionId, durationMs: Date.now() - start, error: String(err) }\n }\n }\n\n // webhook\n try {\n const statusCode = await this.client.triggerWebhookTest(trigger.path)\n const durationMs = Date.now() - start\n if (statusCode >= 200 && statusCode < 300) {\n return { status: 'passed', triggerType: 'webhook', durationMs }\n }\n return { status: 'failed', triggerType: 'webhook', durationMs, error: `Webhook returned HTTP ${statusCode}` }\n } catch (err) {\n return { status: 'error', triggerType: 'webhook', durationMs: Date.now() - start, error: String(err) }\n }\n }\n\n private detectTrigger(workflow: N8nWorkflow): TriggerInfo {\n for (const node of workflow.nodes) {\n if (node.type === 'n8n-nodes-base.manualTrigger') return { type: 'manual' }\n if (node.type === 'n8n-nodes-base.webhook') {\n const params = node.parameters as Record<string, unknown> | undefined\n const path = typeof params?.['path'] === 'string' ? params['path'] : 'webhook'\n return { type: 'webhook', path }\n }\n }\n return { type: 'unsupported' }\n }\n\n private async pollExecution(executionId: string): Promise<ExecutionDetail> {\n const deadline = Date.now() + SMOKE_TEST_TIMEOUT_MS\n for (;;) {\n const execution = await this.client.getExecution(executionId)\n if (execution.status !== 'running' && execution.status !== 'waiting') {\n return execution\n }\n const remaining = deadline - Date.now()\n if (remaining <= 0) break\n await new Promise<void>((resolve) => setTimeout(resolve, Math.min(SMOKE_TEST_POLL_INTERVAL_MS, remaining)))\n }\n throw new ProviderError(`Smoke test: execution ${executionId} did not complete within ${SMOKE_TEST_TIMEOUT_MS}ms`)\n }\n}\n","import { KairosError } from './base.js'\n\nexport class GenerationError extends KairosError {\n constructor(message: string, cause?: unknown) {\n super(message, cause)\n this.name = 'GenerationError'\n }\n}\n","import { KairosError } from './base.js'\n\nexport class ResponseParseError extends KairosError {\n constructor(message: string, cause?: unknown) {\n super(message, cause)\n this.name = 'ResponseParseError'\n }\n}\n","import { KairosError } from './base.js'\nimport type { ValidationIssue } from '../validation/types.js'\nimport type { AttemptMetadata } from '../telemetry/types.js'\n\nexport type { ValidationIssue }\n\nexport class ValidationError extends KairosError {\n constructor(\n message: string,\n public readonly issues: ValidationIssue[],\n public readonly attemptMetadata?: AttemptMetadata[],\n public readonly warnedRules?: number[],\n ) {\n super(message)\n this.name = 'ValidationError'\n }\n}\n","import type { TrustLevel } from '../library/types.js'\nimport type { N8nWorkflow } from '../types/workflow.js'\n\ninterface SafetyResult {\n trustLevel: TrustLevel\n reasons: string[]\n}\n\nconst BLOCKED_NODE_TYPES = new Set([\n 'n8n-nodes-base.code',\n 'n8n-nodes-base.executeCommand',\n 'n8n-nodes-base.ssh',\n])\n\nconst REVIEW_NODE_TYPES = new Set([\n 'n8n-nodes-base.httpRequest',\n])\n\nconst SECRET_PATTERNS = [\n /sk-[a-zA-Z0-9]{20,}/,\n /ghp_[a-zA-Z0-9]{36}/,\n /xoxb-[0-9]+-[0-9]+-[a-zA-Z0-9]+/,\n /AIza[a-zA-Z0-9_-]{35}/,\n /AKIA[A-Z0-9]{16}/,\n]\n\n// Looser prefixes for scanning inside expressions where the full token may be split\n// across string concatenation (e.g. \"ghp_\" + \"sometoken...\"). We flag any expression\n// containing one of these high-signal prefixes for human review.\nconst SECRET_PREFIXES = ['sk-', 'ghp_', 'xoxb-', 'AIza', 'AKIA']\n\nfunction collectExpressionStrings(obj: unknown, out: string[] = []): string[] {\n if (typeof obj === 'string') {\n if (obj.includes('={{')) out.push(obj)\n } else if (Array.isArray(obj)) {\n for (const item of obj) collectExpressionStrings(item, out)\n } else if (obj !== null && typeof obj === 'object') {\n for (const val of Object.values(obj as Record<string, unknown>)) {\n collectExpressionStrings(val, out)\n }\n }\n return out\n}\n\nexport function assessTemplateSafety(workflow: N8nWorkflow): SafetyResult {\n const reasons: string[] = []\n let worst: TrustLevel = 'safe'\n\n const escalate = (level: TrustLevel, reason: string) => {\n reasons.push(reason)\n if (level === 'blocked') worst = 'blocked'\n else if (level === 'review' && worst === 'safe') worst = 'review'\n }\n\n for (const node of workflow.nodes) {\n if (BLOCKED_NODE_TYPES.has(node.type)) {\n escalate('blocked', `Contains ${node.type} node \"${node.name}\"`)\n }\n\n if (REVIEW_NODE_TYPES.has(node.type)) {\n escalate('review', `Contains ${node.type} node \"${node.name}\"`)\n }\n\n // Scan serialized parameters for literal secrets\n const paramStr = JSON.stringify(node.parameters)\n for (const pattern of SECRET_PATTERNS) {\n if (pattern.test(paramStr)) {\n escalate('blocked', `Node \"${node.name}\" parameters contain a hardcoded secret`)\n break\n }\n }\n\n // Scan expression strings for split/concatenated secret prefixes\n // e.g. ={{ \"ghp_\" + variable }} won't match the full regex but the prefix is a red flag\n const expressions = collectExpressionStrings(node.parameters)\n for (const expr of expressions) {\n for (const prefix of SECRET_PREFIXES) {\n if (expr.includes(prefix)) {\n escalate('review', `Node \"${node.name}\" has an expression containing credential-like prefix \"${prefix}\"`)\n break\n }\n }\n }\n }\n\n return { trustLevel: worst, reasons }\n}\n","import type { IWorkflowLibrary, WorkflowMetadataInput } from '../library/types.js'\nimport type { N8nWorkflow, N8nNode } from '../types/workflow.js'\nimport type { ILogger } from '../utils/logger.js'\nimport type { TemplateSearchResponse, TemplateDetailResponse, SyncProgress } from './types.js'\nimport { N8nValidator } from '../validation/validator.js'\nimport { assessTemplateSafety } from './safety.js'\n\nconst N8N_TEMPLATE_API = 'https://api.n8n.io/api/templates'\nconst PAGE_SIZE = 50\nconst DELAY_BETWEEN_FETCHES_MS = 200\n\nconst DEFAULT_SETTINGS: N8nWorkflow['settings'] = {\n executionOrder: 'v1',\n saveManualExecutions: true,\n timezone: 'UTC',\n}\n\nexport interface SyncOptions {\n maxTemplates?: number\n onProgress?: (progress: SyncProgress) => void\n}\n\nexport class TemplateSyncer {\n private readonly validator: N8nValidator\n private readonly logger: ILogger\n\n constructor(\n private readonly library: IWorkflowLibrary,\n logger: ILogger,\n ) {\n this.validator = new N8nValidator()\n this.logger = logger\n }\n\n async sync(options?: SyncOptions): Promise<SyncProgress> {\n const maxTemplates = options?.maxTemplates ?? 500\n\n await this.library.initialize()\n\n const existing = await this.library.list()\n const existingSourceIds = new Set(\n existing\n .filter((w) => w.sourceKind === 'n8n-template' && w.sourceId)\n .map((w) => w.sourceId!),\n )\n\n const progress: SyncProgress = {\n total: 0,\n processed: 0,\n saved: 0,\n skippedPaid: 0,\n skippedDuplicate: 0,\n blocked: 0,\n reviewed: 0,\n }\n\n const templateIds = await this.fetchTemplateIds(maxTemplates, progress)\n\n for (const id of templateIds) {\n if (existingSourceIds.has(String(id))) {\n progress.skippedDuplicate++\n progress.processed++\n options?.onProgress?.(progress)\n continue\n }\n\n try {\n await this.processTemplate(id, progress)\n } catch (err) {\n this.logger.warn(`Failed to process template ${id}`, { err: String(err) })\n }\n\n progress.processed++\n options?.onProgress?.(progress)\n\n await new Promise((resolve) => setTimeout(resolve, DELAY_BETWEEN_FETCHES_MS))\n }\n\n return progress\n }\n\n private async fetchWithBackoff(url: string, maxRetries = 3): Promise<Response> {\n let delayMs = DELAY_BETWEEN_FETCHES_MS\n let lastResponse!: Response\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n lastResponse = await fetch(url)\n if (lastResponse.status !== 429 && lastResponse.status !== 503) return lastResponse\n if (attempt === maxRetries) break\n const retryAfterHeader = lastResponse.headers.get('Retry-After')\n const waitMs = retryAfterHeader ? parseInt(retryAfterHeader, 10) * 1000 : delayMs * Math.pow(2, attempt)\n this.logger.warn(`HTTP ${lastResponse.status} from template API, retrying in ${waitMs}ms`, { url, attempt })\n await new Promise((resolve) => setTimeout(resolve, waitMs))\n }\n return lastResponse\n }\n\n private async fetchTemplateIds(max: number, progress: SyncProgress): Promise<number[]> {\n const ids: number[] = []\n let page = 1\n\n while (ids.length < max) {\n const url = `${N8N_TEMPLATE_API}/search?page=${page}&rows=${PAGE_SIZE}`\n const response = await this.fetchWithBackoff(url)\n if (!response.ok) break\n\n const data = (await response.json()) as TemplateSearchResponse\n progress.total = Math.min(data.totalWorkflows, max)\n\n for (const template of data.workflows) {\n if (ids.length >= max) break\n if (template.price && template.price > 0) {\n progress.skippedPaid++\n continue\n }\n ids.push(template.id)\n }\n\n if (data.workflows.length < PAGE_SIZE) break\n page++\n\n await new Promise((resolve) => setTimeout(resolve, DELAY_BETWEEN_FETCHES_MS))\n }\n\n return ids\n }\n\n private async processTemplate(id: number, progress: SyncProgress): Promise<void> {\n const url = `${N8N_TEMPLATE_API}/workflows/${id}`\n const response = await this.fetchWithBackoff(url)\n if (!response.ok) return\n\n const data = (await response.json()) as TemplateDetailResponse\n const templateMeta = data.workflow\n const rawWorkflow = templateMeta.workflow\n\n if (!rawWorkflow?.nodes?.length) return\n\n const workflow: N8nWorkflow = {\n name: templateMeta.name,\n nodes: rawWorkflow.nodes.filter((n) => n.type && n.name) as N8nNode[],\n connections: rawWorkflow.connections as N8nWorkflow['connections'],\n settings: rawWorkflow.settings\n ? { executionOrder: 'v1' as const, ...rawWorkflow.settings }\n : { ...DEFAULT_SETTINGS },\n }\n\n const validation = this.validator.validate(workflow)\n const validationErrors = validation.issues.filter((i) => i.severity === 'error')\n\n if (validationErrors.length > 0) {\n progress.blocked++\n this.logger.debug(`Template ${id} blocked: ${validationErrors.length} validation errors`)\n return\n }\n\n const safety = assessTemplateSafety(workflow)\n\n if (safety.trustLevel === 'blocked') {\n progress.blocked++\n this.logger.debug(`Template ${id} blocked: ${safety.reasons.join(', ')}`)\n return\n }\n\n if (safety.trustLevel === 'review') {\n progress.reviewed++\n }\n\n const description = this.cleanDescription(templateMeta.description)\n\n const autoTags = Array.from(new Set(\n workflow.nodes.flatMap((n) => {\n const bare = n.type.split('.').pop() ?? ''\n const tags = [bare]\n if (n.type.includes('Trigger') || n.type.includes('trigger')) tags.push(`trigger:${bare}`)\n if (n.type.includes('langchain')) tags.push('ai')\n return tags\n }),\n ))\n\n const metadata: WorkflowMetadataInput = {\n description,\n tags: autoTags,\n sourceKind: 'n8n-template',\n sourceId: String(id),\n sourceUrl: `https://n8n.io/workflows/${id}`,\n trustLevel: safety.trustLevel,\n }\n\n await this.library.save(workflow, metadata)\n progress.saved++\n this.logger.debug(`Template ${id} saved: \"${templateMeta.name}\" (${safety.trustLevel})`)\n }\n\n private cleanDescription(raw: string): string {\n return raw\n .replace(/#{1,6}\\s*/g, '')\n .replace(/\\*{1,2}([^*]+)\\*{1,2}/g, '$1')\n .replace(/\\[([^\\]]+)\\]\\([^)]+\\)/g, '$1')\n .replace(/\\n{3,}/g, '\\n\\n')\n .trim()\n .slice(0, 500)\n }\n}\n"],"mappings":"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","names":[]}