@qodo/sdk 0.7.0 → 0.9.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.
- package/.claude/skills/qodo-agent/SKILL.md +268 -3
- package/.claude/skills/qodo-agent/assets/programmatic-agent.ts +90 -1
- package/.claude/skills/qodo-agent/references/common-issues.md +80 -0
- package/dist/api/agent.d.ts.map +1 -1
- package/dist/api/agent.js +13 -8
- package/dist/api/agent.js.map +1 -1
- package/dist/api/http.d.ts.map +1 -1
- package/dist/api/http.js +5 -2
- package/dist/api/http.js.map +1 -1
- package/dist/api/websocket.d.ts.map +1 -1
- package/dist/api/websocket.js +6 -3
- package/dist/api/websocket.js.map +1 -1
- package/dist/auth/index.d.ts +18 -0
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js +69 -10
- package/dist/auth/index.js.map +1 -1
- package/dist/context/messageManager.d.ts +1 -1
- package/dist/context/messageManager.d.ts.map +1 -1
- package/dist/context/messageManager.js +1 -1
- package/dist/context/messageManager.js.map +1 -1
- package/dist/index.d.ts +21 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -1
- package/dist/index.js.map +1 -1
- package/dist/mcp/MCPManager.js +2 -2
- package/dist/mcp/MCPManager.js.map +1 -1
- package/dist/mcp/baseServer.js +1 -1
- package/dist/mcp/baseServer.js.map +1 -1
- package/dist/mcp/servers/ripgrep.d.ts.map +1 -1
- package/dist/mcp/servers/ripgrep.js +6 -2
- package/dist/mcp/servers/ripgrep.js.map +1 -1
- package/dist/mcp/servers/shell.js +1 -1
- package/dist/mcp/servers/shell.js.map +1 -1
- package/dist/mcp/serversRegistry.d.ts.map +1 -1
- package/dist/mcp/serversRegistry.js +7 -1
- package/dist/mcp/serversRegistry.js.map +1 -1
- package/dist/mcp/toolProcessor.d.ts +44 -4
- package/dist/mcp/toolProcessor.d.ts.map +1 -1
- package/dist/mcp/toolProcessor.js +255 -20
- package/dist/mcp/toolProcessor.js.map +1 -1
- package/dist/messages/index.d.ts +8 -0
- package/dist/messages/index.d.ts.map +1 -0
- package/dist/messages/index.js +7 -0
- package/dist/messages/index.js.map +1 -0
- package/dist/messages/openai.d.ts +26 -0
- package/dist/messages/openai.d.ts.map +1 -0
- package/dist/messages/openai.js +55 -0
- package/dist/messages/openai.js.map +1 -0
- package/dist/messages/types.d.ts +73 -0
- package/dist/messages/types.d.ts.map +1 -0
- package/dist/messages/types.js +78 -0
- package/dist/messages/types.js.map +1 -0
- package/dist/parser/index.js +3 -3
- package/dist/parser/index.js.map +1 -1
- package/dist/sdk/QodoSDK.d.ts +30 -10
- package/dist/sdk/QodoSDK.d.ts.map +1 -1
- package/dist/sdk/QodoSDK.js +165 -33
- package/dist/sdk/QodoSDK.js.map +1 -1
- package/dist/sdk/artifacts.d.ts +156 -0
- package/dist/sdk/artifacts.d.ts.map +1 -0
- package/dist/sdk/artifacts.js +166 -0
- package/dist/sdk/artifacts.js.map +1 -0
- package/dist/sdk/bootstrap.d.ts.map +1 -1
- package/dist/sdk/bootstrap.js +11 -4
- package/dist/sdk/bootstrap.js.map +1 -1
- package/dist/sdk/discovery.js +1 -1
- package/dist/sdk/discovery.js.map +1 -1
- package/dist/sdk/events.d.ts +53 -1
- package/dist/sdk/events.d.ts.map +1 -1
- package/dist/sdk/events.js +7 -0
- package/dist/sdk/events.js.map +1 -1
- package/dist/sdk/middleware.d.ts +59 -0
- package/dist/sdk/middleware.d.ts.map +1 -0
- package/dist/sdk/middleware.js +69 -0
- package/dist/sdk/middleware.js.map +1 -0
- package/dist/sdk/pipeline/PipelineBuilder.d.ts +79 -0
- package/dist/sdk/pipeline/PipelineBuilder.d.ts.map +1 -0
- package/dist/sdk/pipeline/PipelineBuilder.js +129 -0
- package/dist/sdk/pipeline/PipelineBuilder.js.map +1 -0
- package/dist/sdk/pipeline/PipelineRunner.d.ts +28 -0
- package/dist/sdk/pipeline/PipelineRunner.d.ts.map +1 -0
- package/dist/sdk/pipeline/PipelineRunner.js +326 -0
- package/dist/sdk/pipeline/PipelineRunner.js.map +1 -0
- package/dist/sdk/pipeline/compiler.d.ts +24 -0
- package/dist/sdk/pipeline/compiler.d.ts.map +1 -0
- package/dist/sdk/pipeline/compiler.js +199 -0
- package/dist/sdk/pipeline/compiler.js.map +1 -0
- package/dist/sdk/pipeline/declarative.d.ts +34 -0
- package/dist/sdk/pipeline/declarative.d.ts.map +1 -0
- package/dist/sdk/pipeline/declarative.js +9 -0
- package/dist/sdk/pipeline/declarative.js.map +1 -0
- package/dist/sdk/pipeline/index.d.ts +20 -0
- package/dist/sdk/pipeline/index.d.ts.map +1 -0
- package/dist/sdk/pipeline/index.js +19 -0
- package/dist/sdk/pipeline/index.js.map +1 -0
- package/dist/sdk/pipeline/types.d.ts +93 -0
- package/dist/sdk/pipeline/types.d.ts.map +1 -0
- package/dist/sdk/pipeline/types.js +10 -0
- package/dist/sdk/pipeline/types.js.map +1 -0
- package/dist/sdk/policies.d.ts +163 -0
- package/dist/sdk/policies.d.ts.map +1 -0
- package/dist/sdk/policies.js +243 -0
- package/dist/sdk/policies.js.map +1 -0
- package/dist/sdk/runner/AgentRunner.js +5 -5
- package/dist/sdk/runner/AgentRunner.js.map +1 -1
- package/dist/sdk/runner/finalize.d.ts +47 -0
- package/dist/sdk/runner/finalize.d.ts.map +1 -1
- package/dist/sdk/runner/finalize.js +42 -2
- package/dist/sdk/runner/finalize.js.map +1 -1
- package/dist/sdk/runner/formats.d.ts +1 -1
- package/dist/sdk/runner/formats.d.ts.map +1 -1
- package/dist/sdk/runner/formats.js +22 -37
- package/dist/sdk/runner/formats.js.map +1 -1
- package/dist/sdk/runner/progress.d.ts +1 -1
- package/dist/sdk/runner/progress.d.ts.map +1 -1
- package/dist/sdk/runner/progress.js +1 -1
- package/dist/sdk/runner/progress.js.map +1 -1
- package/dist/session/SessionContext.d.ts +1 -0
- package/dist/session/SessionContext.d.ts.map +1 -1
- package/dist/session/SessionContext.js +3 -0
- package/dist/session/SessionContext.js.map +1 -1
- package/dist/session/environment.d.ts +16 -6
- package/dist/session/environment.d.ts.map +1 -1
- package/dist/session/environment.js.map +1 -1
- package/dist/session/serverData.d.ts.map +1 -1
- package/dist/session/serverData.js +21 -3
- package/dist/session/serverData.js.map +1 -1
- package/dist/tracing/PipelineTracer.d.ts +37 -0
- package/dist/tracing/PipelineTracer.d.ts.map +1 -0
- package/dist/tracing/PipelineTracer.js +80 -0
- package/dist/tracing/PipelineTracer.js.map +1 -0
- package/dist/tracing/SdkTracer.d.ts +91 -0
- package/dist/tracing/SdkTracer.d.ts.map +1 -0
- package/dist/tracing/SdkTracer.js +243 -0
- package/dist/tracing/SdkTracer.js.map +1 -0
- package/dist/tracing/index.d.ts +6 -0
- package/dist/tracing/index.d.ts.map +1 -0
- package/dist/tracing/index.js +3 -0
- package/dist/tracing/index.js.map +1 -0
- package/dist/tracing/pipelineHelpers.d.ts +29 -0
- package/dist/tracing/pipelineHelpers.d.ts.map +1 -0
- package/dist/tracing/pipelineHelpers.js +224 -0
- package/dist/tracing/pipelineHelpers.js.map +1 -0
- package/dist/tracing/types.d.ts +46 -0
- package/dist/tracing/types.d.ts.map +1 -0
- package/dist/tracing/types.js +9 -0
- package/dist/tracing/types.js.map +1 -0
- package/package.json +10 -7
|
@@ -39,6 +39,51 @@ Use this skill when working with `@qodo/sdk` to build AI-powered agents. This sk
|
|
|
39
39
|
| `parseArgsWithSchema()` | Validate args with Zod, get typed result |
|
|
40
40
|
| `QodoSchemaError` | Schema validation error class |
|
|
41
41
|
|
|
42
|
+
### Pipeline DSL
|
|
43
|
+
|
|
44
|
+
| Export | Purpose |
|
|
45
|
+
|--------|---------|
|
|
46
|
+
| `sdkPipeline()` | Build multi-step agent workflows |
|
|
47
|
+
| `runPipeline()` | Execute a pipeline with an SDK instance |
|
|
48
|
+
| `PipelineExecutionError` | Pipeline step failure error |
|
|
49
|
+
| `.step()` | Add a sequential step with typed state threading |
|
|
50
|
+
| `.parallel()` | Add a group of steps that execute concurrently |
|
|
51
|
+
| `.gate()` | Pipeline-level barrier — halts subsequent entries when false |
|
|
52
|
+
| `.branch()` | Pipeline-level if/else fork with sub-pipeline paths |
|
|
53
|
+
|
|
54
|
+
### Tool Middleware
|
|
55
|
+
|
|
56
|
+
| Export | Purpose |
|
|
57
|
+
|--------|---------|
|
|
58
|
+
| `ToolMiddleware` (type) | Pre/post execution hook interface |
|
|
59
|
+
| `ToolMiddlewareError` | Middleware failure error |
|
|
60
|
+
| `MIDDLEWARE_TIMEOUT_MS` | Default hook timeout (10s) |
|
|
61
|
+
| `PROTECTED_TOOL_FIELDS` | Fields middleware cannot overwrite |
|
|
62
|
+
|
|
63
|
+
### Tool Approval Policies
|
|
64
|
+
|
|
65
|
+
| Export | Purpose |
|
|
66
|
+
|--------|---------|
|
|
67
|
+
| `sdkPolicy()` | Fluent builder for declarative tool approval rules |
|
|
68
|
+
| `policyFromRules()` | Build a policy from a rule array |
|
|
69
|
+
| `globMatch()` | Glob pattern matching utility |
|
|
70
|
+
|
|
71
|
+
### Artifacts
|
|
72
|
+
|
|
73
|
+
| Export | Purpose |
|
|
74
|
+
|--------|---------|
|
|
75
|
+
| `ArtifactStore` | Store/persist intermediate pipeline results |
|
|
76
|
+
| `withArtifacts()` | Wrap a pipeline step to auto-store output |
|
|
77
|
+
| `jsonSerializer` | Default JSON serializer |
|
|
78
|
+
|
|
79
|
+
### OpenTelemetry Tracing
|
|
80
|
+
|
|
81
|
+
| Export | Purpose |
|
|
82
|
+
|--------|---------|
|
|
83
|
+
| `createSdkTracer()` | Create event-to-span tracer (duck-typed OTel API) |
|
|
84
|
+
| `tracePipeline()` | Trace pipeline execution with nested spans |
|
|
85
|
+
| `SdkTracer` | Tracer class for manual usage |
|
|
86
|
+
|
|
42
87
|
### Event Handling
|
|
43
88
|
|
|
44
89
|
| Export | Purpose |
|
|
@@ -60,6 +105,9 @@ Use this skill when working with `@qodo/sdk` to build AI-powered agents. This sk
|
|
|
60
105
|
| `QodoSchemaError` | Schema validation failures |
|
|
61
106
|
| `QodoAuthError` | Authentication failures |
|
|
62
107
|
| `QodoBackendBootstrapError` | Backend initialization failures |
|
|
108
|
+
| `QodoOutputValidationError` | Structured output didn't match Zod schema |
|
|
109
|
+
| `ToolMiddlewareError` | Tool middleware hook failure |
|
|
110
|
+
| `PipelineExecutionError` | Pipeline step failure |
|
|
63
111
|
|
|
64
112
|
### Built-in Tools
|
|
65
113
|
|
|
@@ -437,6 +485,209 @@ try {
|
|
|
437
485
|
}
|
|
438
486
|
```
|
|
439
487
|
|
|
488
|
+
### Pattern 8: Pipeline DSL (Multi-Step Workflows)
|
|
489
|
+
|
|
490
|
+
```typescript
|
|
491
|
+
import { QodoSDK, sdkPipeline, runPipeline } from '@qodo/sdk';
|
|
492
|
+
|
|
493
|
+
const sdk = new QodoSDK({ autoApproveTools: true });
|
|
494
|
+
|
|
495
|
+
const pipeline = sdkPipeline<{ repo: string }>()
|
|
496
|
+
.step('lint', async ({ state, run }) => {
|
|
497
|
+
const r = await run('lint', { args: { path: state.repo } });
|
|
498
|
+
return { lintOutput: r.result.final_output };
|
|
499
|
+
})
|
|
500
|
+
// Gate: only continue review if lint produced output
|
|
501
|
+
.gate((state) => !!state.lintOutput)
|
|
502
|
+
.step('review', async ({ state, run }) => {
|
|
503
|
+
const r = await run('review', {
|
|
504
|
+
extraInstructions: `Lint results:\n${state.lintOutput}`,
|
|
505
|
+
});
|
|
506
|
+
return { reviewOutput: r.result.final_output };
|
|
507
|
+
})
|
|
508
|
+
.build();
|
|
509
|
+
|
|
510
|
+
const result = await runPipeline(sdk, pipeline, { repo: './src' });
|
|
511
|
+
console.log(result.state.reviewOutput);
|
|
512
|
+
console.log(result.steps); // Step logs with timing
|
|
513
|
+
|
|
514
|
+
await sdk.dispose();
|
|
515
|
+
```
|
|
516
|
+
|
|
517
|
+
Features: typed state threading, `.parallel([...])`, `.gate()` (pipeline barriers), `.branch()` (if/else forks), error strategies (`'skip'`, `'throw'`, custom recovery).
|
|
518
|
+
|
|
519
|
+
### Pattern 8b: Pipeline Branches
|
|
520
|
+
|
|
521
|
+
```typescript
|
|
522
|
+
import { QodoSDK, sdkPipeline, runPipeline } from '@qodo/sdk';
|
|
523
|
+
|
|
524
|
+
const sdk = new QodoSDK({ autoApproveTools: true });
|
|
525
|
+
|
|
526
|
+
const pipeline = sdkPipeline<{ fileCount: number }>()
|
|
527
|
+
.branch(
|
|
528
|
+
(state) => state.fileCount > 20,
|
|
529
|
+
{
|
|
530
|
+
true: (b) => b.step('deep', async ({ run }) => {
|
|
531
|
+
const r = await run('analyze-deep');
|
|
532
|
+
return { analysis: r.result.final_output };
|
|
533
|
+
}),
|
|
534
|
+
false: (b) => b.step('quick', async ({ run }) => {
|
|
535
|
+
const r = await run('summarize');
|
|
536
|
+
return { analysis: r.result.final_output };
|
|
537
|
+
}),
|
|
538
|
+
},
|
|
539
|
+
{ name: 'size-check' },
|
|
540
|
+
)
|
|
541
|
+
.step('report', async ({ state }) => ({
|
|
542
|
+
report: `${state.fileCount} files: ${state.analysis}`,
|
|
543
|
+
}))
|
|
544
|
+
.build();
|
|
545
|
+
|
|
546
|
+
await sdk.dispose();
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
### Pattern 9: Dry Run Mode
|
|
550
|
+
|
|
551
|
+
```typescript
|
|
552
|
+
import { QodoSDK } from '@qodo/sdk';
|
|
553
|
+
|
|
554
|
+
const sdk = new QodoSDK({ autoApproveTools: true });
|
|
555
|
+
|
|
556
|
+
// Preview what the agent would do without executing tools
|
|
557
|
+
const result = await sdk.run('review', {
|
|
558
|
+
args: { path: './src' },
|
|
559
|
+
dryRun: true,
|
|
560
|
+
});
|
|
561
|
+
|
|
562
|
+
console.log(result.result.final_output); // Agent describes planned actions
|
|
563
|
+
console.log(result.meta.dry_run); // true
|
|
564
|
+
|
|
565
|
+
await sdk.dispose();
|
|
566
|
+
```
|
|
567
|
+
|
|
568
|
+
### Pattern 10: Tool Middleware (Auditing & Control)
|
|
569
|
+
|
|
570
|
+
```typescript
|
|
571
|
+
import { QodoSDK, type ToolMiddleware } from '@qodo/sdk';
|
|
572
|
+
|
|
573
|
+
const auditLogger: ToolMiddleware = {
|
|
574
|
+
name: 'audit-logger',
|
|
575
|
+
preExecute(toolData) {
|
|
576
|
+
console.log(`[AUDIT] ${toolData.server_name}.${toolData.tool_name}`);
|
|
577
|
+
},
|
|
578
|
+
postExecute(toolData, result) {
|
|
579
|
+
console.log(`[AUDIT] Result: ${result.isError ? 'ERROR' : 'OK'}`);
|
|
580
|
+
},
|
|
581
|
+
};
|
|
582
|
+
|
|
583
|
+
const readOnly: ToolMiddleware = {
|
|
584
|
+
name: 'read-only',
|
|
585
|
+
preExecute(toolData) {
|
|
586
|
+
if (['write_file', 'edit_file', 'delete_files'].includes(toolData.tool_name)) {
|
|
587
|
+
throw new Error(`Blocked: ${toolData.tool_name}`);
|
|
588
|
+
}
|
|
589
|
+
},
|
|
590
|
+
};
|
|
591
|
+
|
|
592
|
+
const sdk = new QodoSDK({
|
|
593
|
+
autoApproveTools: true,
|
|
594
|
+
toolMiddleware: [auditLogger, readOnly],
|
|
595
|
+
});
|
|
596
|
+
```
|
|
597
|
+
|
|
598
|
+
### Pattern 11: Tool Approval Policy DSL
|
|
599
|
+
|
|
600
|
+
```typescript
|
|
601
|
+
import { QodoSDK, sdkPolicy } from '@qodo/sdk';
|
|
602
|
+
|
|
603
|
+
const policy = sdkPolicy()
|
|
604
|
+
.approve({ tools: ['read_*', 'list_*', 'git_status', 'git_log'] }, 'allow-reads')
|
|
605
|
+
.deny({ servers: ['shell'] }, 'block-shell')
|
|
606
|
+
.deny({ tools: ['write_file', 'edit_file', 'delete_files'] }, 'block-writes')
|
|
607
|
+
.requireHuman({ tools: ['git_commit'] }, 'review-commits')
|
|
608
|
+
.default('deny')
|
|
609
|
+
.build();
|
|
610
|
+
|
|
611
|
+
const sdk = new QodoSDK({
|
|
612
|
+
autoApproveTools: false,
|
|
613
|
+
toolApproval: policy.evaluate,
|
|
614
|
+
});
|
|
615
|
+
|
|
616
|
+
// Inspect policy decisions:
|
|
617
|
+
const result = policy.evaluateDetailed({
|
|
618
|
+
tool_name: 'read_files', server_name: 'filesystem', tool_args: {},
|
|
619
|
+
});
|
|
620
|
+
console.log(result.decision, result.matchedRule?.name); // 'approve', 'allow-reads'
|
|
621
|
+
```
|
|
622
|
+
|
|
623
|
+
### Pattern 12: Execution Timeouts and Retries
|
|
624
|
+
|
|
625
|
+
```typescript
|
|
626
|
+
import { QodoSDK } from '@qodo/sdk';
|
|
627
|
+
|
|
628
|
+
const sdk = new QodoSDK({ autoApproveTools: true });
|
|
629
|
+
|
|
630
|
+
const result = await sdk.run('review', {
|
|
631
|
+
args: { path: './src' },
|
|
632
|
+
timeout: 30000, // 30 second limit per attempt
|
|
633
|
+
maxRetries: 2, // Retry up to 2 times on failure
|
|
634
|
+
});
|
|
635
|
+
|
|
636
|
+
if (result.meta.timed_out) {
|
|
637
|
+
console.warn('Run timed out');
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
await sdk.dispose();
|
|
641
|
+
```
|
|
642
|
+
|
|
643
|
+
### Pattern 13: Artifacts (Pipeline Intermediate Results)
|
|
644
|
+
|
|
645
|
+
```typescript
|
|
646
|
+
import { QodoSDK, sdkPipeline, runPipeline, ArtifactStore, withArtifacts } from '@qodo/sdk';
|
|
647
|
+
import fs from 'fs/promises';
|
|
648
|
+
|
|
649
|
+
const store = new ArtifactStore({
|
|
650
|
+
onPersist: async (artifact) => {
|
|
651
|
+
await fs.writeFile(`./out/${artifact.stepName}.json`, artifact.serialized);
|
|
652
|
+
},
|
|
653
|
+
});
|
|
654
|
+
|
|
655
|
+
const pipeline = sdkPipeline<{ repo: string }>()
|
|
656
|
+
.step('lint', withArtifacts(store, async ({ state, run }) => {
|
|
657
|
+
const r = await run('lint', { args: { path: state.repo } });
|
|
658
|
+
return { lintOutput: r.result.final_output };
|
|
659
|
+
}))
|
|
660
|
+
.build();
|
|
661
|
+
|
|
662
|
+
const result = await runPipeline(sdk, pipeline, { repo: './src' });
|
|
663
|
+
console.log(store.all()); // All artifacts
|
|
664
|
+
console.log(store.getErrors()); // Persistence failures (non-fatal)
|
|
665
|
+
```
|
|
666
|
+
|
|
667
|
+
### Pattern 14: OpenTelemetry Tracing
|
|
668
|
+
|
|
669
|
+
```typescript
|
|
670
|
+
import * as otel from '@opentelemetry/api';
|
|
671
|
+
import { QodoSDK, createSdkTracer, SdkEventType, matchSdkEvent } from '@qodo/sdk';
|
|
672
|
+
|
|
673
|
+
const sdk = new QodoSDK({ autoApproveTools: true });
|
|
674
|
+
const tracer = createSdkTracer(otel, { tracerName: 'my-service' });
|
|
675
|
+
|
|
676
|
+
// Events flow through unchanged, spans created automatically
|
|
677
|
+
for await (const ev of tracer.wrapStream(sdk.stream('review'))) {
|
|
678
|
+
matchSdkEvent(ev, {
|
|
679
|
+
[SdkEventType.MessageDelta]: (e) => process.stdout.write(e.data.delta),
|
|
680
|
+
[SdkEventType.Final]: (e) => console.log('Done:', e.data.success),
|
|
681
|
+
default: () => {},
|
|
682
|
+
});
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
tracer.flush();
|
|
686
|
+
await sdk.dispose();
|
|
687
|
+
```
|
|
688
|
+
|
|
689
|
+
No compile-time OTel dependency — install `@opentelemetry/api` as optional peer dep.
|
|
690
|
+
|
|
440
691
|
---
|
|
441
692
|
|
|
442
693
|
## Zod Schema Patterns
|
|
@@ -519,15 +770,15 @@ const args = z.object({
|
|
|
519
770
|
| Event Type | When Emitted | Key Data Fields |
|
|
520
771
|
|------------|--------------|-----------------|
|
|
521
772
|
| `sdk.init` | SDK initialized | `sdk_version`, `backend.base_url`, `model` |
|
|
522
|
-
| `sdk.run.started` | Run begins | `session_id`, `command`, `prompt_mode`, `cwd` |
|
|
773
|
+
| `sdk.run.started` | Run begins | `session_id`, `command`, `prompt_mode`, `cwd`, `dry_run?` |
|
|
523
774
|
| `sdk.message.delta` | Streaming text | `delta`, `message_id`, `role` |
|
|
524
775
|
| `sdk.message.full` | Full message update | `messages.langchain`, `messages.openai` |
|
|
525
776
|
| `sdk.progress` | Progress update | `title`, `status`, `percent` |
|
|
526
777
|
| `sdk.tool.requested` | Tool call requested | `tool_call_id`, `server_name`, `tool_name`, `tool_args`, `pending_approval` |
|
|
527
778
|
| `sdk.tool.approved` | Tool approved/denied | `tool_call_id`, `approved`, `reason` |
|
|
528
|
-
| `sdk.tool.executed` | Tool finished | `tool_call_id`, `result.isError`, `result.content` |
|
|
779
|
+
| `sdk.tool.executed` | Tool finished | `tool_call_id`, `result.isError`, `result.content`, `dry_run?` |
|
|
529
780
|
| `sdk.error` | Error occurred | `message`, `cause` |
|
|
530
|
-
| `sdk.final` | Run completed | `success`, `result.structured_output`, `result.final_output`, `
|
|
781
|
+
| `sdk.final` | Run completed | `success`, `result.structured_output`, `result.final_output`, `meta.dry_run?`, `meta.timed_out?` |
|
|
531
782
|
|
|
532
783
|
---
|
|
533
784
|
|
|
@@ -552,6 +803,7 @@ interface QodoSDKOptions {
|
|
|
552
803
|
// Tool handling
|
|
553
804
|
autoApproveTools?: boolean; // Auto-approve tools (default: true)
|
|
554
805
|
toolApproval?: (req) => Promise<boolean> | boolean; // Custom approval
|
|
806
|
+
toolMiddleware?: ToolMiddleware[]; // Pre/post execution hooks
|
|
555
807
|
|
|
556
808
|
// Session
|
|
557
809
|
contextSessionIds?: string[]; // Previous sessions for context
|
|
@@ -654,3 +906,16 @@ z.object({
|
|
|
654
906
|
- [assets/programmatic-agent.ts](assets/programmatic-agent.ts) - Complete working TypeScript agent template
|
|
655
907
|
- [references/builtin-tools.md](references/builtin-tools.md) - Detailed guide to filesystem, git, ripgrep, and shell tools
|
|
656
908
|
- [references/common-issues.md](references/common-issues.md) - Troubleshooting guide for common problems
|
|
909
|
+
|
|
910
|
+
### Documentation (in `docs/`)
|
|
911
|
+
|
|
912
|
+
| Feature | Doc |
|
|
913
|
+
|---------|-----|
|
|
914
|
+
| Pipeline DSL | [docs/pipeline.md](../../../docs/pipeline.md) |
|
|
915
|
+
| Dry Run Mode | [docs/dry-run.md](../../../docs/dry-run.md) |
|
|
916
|
+
| Tool Middleware | [docs/tool-middleware.md](../../../docs/tool-middleware.md) |
|
|
917
|
+
| Structured Output | [docs/structured-output.md](../../../docs/structured-output.md) |
|
|
918
|
+
| Execution Timeouts | [docs/execution-timeouts.md](../../../docs/execution-timeouts.md) |
|
|
919
|
+
| OpenTelemetry | [docs/opentelemetry.md](../../../docs/opentelemetry.md) |
|
|
920
|
+
| Approval Policies | [docs/approval-policies.md](../../../docs/approval-policies.md) |
|
|
921
|
+
| Artifacts | [docs/artifacts.md](../../../docs/artifacts.md) |
|
|
@@ -5,6 +5,10 @@
|
|
|
5
5
|
* - sdkAgent() and sdkCommand() builders
|
|
6
6
|
* - Zod schemas with proper descriptions
|
|
7
7
|
* - Event streaming with matchSdkEvent()
|
|
8
|
+
* - Pipeline DSL with typed state threading
|
|
9
|
+
* - Tool middleware for auditing
|
|
10
|
+
* - Dry run mode
|
|
11
|
+
* - Execution timeouts
|
|
8
12
|
* - Error handling
|
|
9
13
|
* - Proper cleanup with dispose()
|
|
10
14
|
*
|
|
@@ -23,7 +27,11 @@ import {
|
|
|
23
27
|
zJsonAny,
|
|
24
28
|
QodoSchemaError,
|
|
25
29
|
QodoAuthError,
|
|
26
|
-
|
|
30
|
+
QodoOutputValidationError,
|
|
31
|
+
sdkPipeline,
|
|
32
|
+
runPipeline,
|
|
33
|
+
z,
|
|
34
|
+
type ToolMiddleware,
|
|
27
35
|
} from '@qodo/sdk';
|
|
28
36
|
|
|
29
37
|
// =============================================================================
|
|
@@ -180,6 +188,17 @@ Guidelines:
|
|
|
180
188
|
// =============================================================================
|
|
181
189
|
|
|
182
190
|
async function main() {
|
|
191
|
+
// Optional: create tool middleware for auditing
|
|
192
|
+
const auditMiddleware: ToolMiddleware = {
|
|
193
|
+
name: 'audit',
|
|
194
|
+
preExecute(toolData) {
|
|
195
|
+
console.log(` [audit] >>> ${toolData.server_name}.${toolData.tool_name}`);
|
|
196
|
+
},
|
|
197
|
+
postExecute(toolData, result) {
|
|
198
|
+
console.log(` [audit] <<< ${result.isError ? 'ERROR' : 'OK'}`);
|
|
199
|
+
},
|
|
200
|
+
};
|
|
201
|
+
|
|
183
202
|
// Create SDK from the agent configuration
|
|
184
203
|
const sdk = QodoSDK.fromAgent(codeAssistantAgent, {
|
|
185
204
|
// Optional: override project path (defaults to cwd)
|
|
@@ -188,6 +207,9 @@ async function main() {
|
|
|
188
207
|
// Optional: enable debug logging
|
|
189
208
|
// debug: true,
|
|
190
209
|
|
|
210
|
+
// Optional: tool middleware for auditing, rate limiting, etc.
|
|
211
|
+
toolMiddleware: [auditMiddleware],
|
|
212
|
+
|
|
191
213
|
// Optional: custom tool approval (default: auto-approve)
|
|
192
214
|
// autoApproveTools: false,
|
|
193
215
|
// toolApproval: async ({ tool_name, tool_args }) => {
|
|
@@ -296,6 +318,70 @@ async function main() {
|
|
|
296
318
|
);
|
|
297
319
|
// @ts-ignore
|
|
298
320
|
console.log('Response:', promptResult.final_output);
|
|
321
|
+
// -------------------------------------------------------------------------
|
|
322
|
+
// Example 4: Pipeline (multi-step workflow with gates and branches)
|
|
323
|
+
// -------------------------------------------------------------------------
|
|
324
|
+
console.log('\n\n--- Pipeline example ---\n');
|
|
325
|
+
|
|
326
|
+
const pipeline = sdkPipeline<{ path: string }>()
|
|
327
|
+
.step('analyze', async ({ state, run }) => {
|
|
328
|
+
const r = await run('analyze', { args: { path: state.path } });
|
|
329
|
+
return { analysis: r.result.structured_output };
|
|
330
|
+
})
|
|
331
|
+
// Gate: only continue if analysis produced results
|
|
332
|
+
.gate((state) => !!state.analysis, { name: 'has-analysis' })
|
|
333
|
+
// Branch: choose different summary strategies based on score
|
|
334
|
+
.branch(
|
|
335
|
+
(state) => (state.analysis as any)?.score > 80,
|
|
336
|
+
{
|
|
337
|
+
true: (b) => b.step('brief-summary', async ({ state, run }) => {
|
|
338
|
+
const r = await run('', {
|
|
339
|
+
extraInstructions: `High quality code (score: ${(state.analysis as any)?.score}). Brief summary: ${JSON.stringify(state.analysis)}`,
|
|
340
|
+
});
|
|
341
|
+
return { summary: r.result.final_output };
|
|
342
|
+
}),
|
|
343
|
+
false: (b) => b.step('detailed-summary', async ({ state, run }) => {
|
|
344
|
+
const r = await run('', {
|
|
345
|
+
extraInstructions: `Code needs improvement. Detailed summary with recommendations: ${JSON.stringify(state.analysis)}`,
|
|
346
|
+
});
|
|
347
|
+
return { summary: r.result.final_output };
|
|
348
|
+
}),
|
|
349
|
+
},
|
|
350
|
+
{ name: 'quality-check' },
|
|
351
|
+
)
|
|
352
|
+
.build();
|
|
353
|
+
|
|
354
|
+
const pipelineResult = await runPipeline(sdk, pipeline, { path: './src' });
|
|
355
|
+
console.log('Pipeline summary:', pipelineResult.state.summary);
|
|
356
|
+
for (const log of pipelineResult.steps) {
|
|
357
|
+
const branch = log.branchTaken ? ` (branch: ${log.branchTaken})` : '';
|
|
358
|
+
console.log(` ${log.name}: ${log.status}${branch} (${log.durationMs}ms)`);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// -------------------------------------------------------------------------
|
|
362
|
+
// Example 5: Dry run mode (preview without side effects)
|
|
363
|
+
// -------------------------------------------------------------------------
|
|
364
|
+
console.log('\n\n--- Dry run example ---\n');
|
|
365
|
+
|
|
366
|
+
const dryResult = await sdk.run('analyze', {
|
|
367
|
+
args: { path: './src' },
|
|
368
|
+
dryRun: true,
|
|
369
|
+
});
|
|
370
|
+
console.log('Dry run output:', dryResult.result.final_output?.slice(0, 200));
|
|
371
|
+
console.log('Was dry run:', dryResult.meta.dry_run);
|
|
372
|
+
|
|
373
|
+
// -------------------------------------------------------------------------
|
|
374
|
+
// Example 6: Execution timeout with retry
|
|
375
|
+
// -------------------------------------------------------------------------
|
|
376
|
+
console.log('\n\n--- Timeout example ---\n');
|
|
377
|
+
|
|
378
|
+
const timedResult = await sdk.run('analyze', {
|
|
379
|
+
args: { path: './src' },
|
|
380
|
+
timeout: 60000, // 60 second limit
|
|
381
|
+
maxRetries: 1, // Retry once on failure
|
|
382
|
+
});
|
|
383
|
+
console.log('Timed out:', timedResult.meta.timed_out ?? false);
|
|
384
|
+
|
|
299
385
|
} catch (error) {
|
|
300
386
|
// Handle specific error types
|
|
301
387
|
if (error instanceof QodoSchemaError) {
|
|
@@ -304,6 +390,9 @@ async function main() {
|
|
|
304
390
|
} else if (error instanceof QodoAuthError) {
|
|
305
391
|
console.error('Authentication error:', error.message);
|
|
306
392
|
console.error('Check your QODO_API_KEY environment variable');
|
|
393
|
+
} else if (error instanceof QodoOutputValidationError) {
|
|
394
|
+
console.error('Output validation error:', error.issues);
|
|
395
|
+
console.error('Raw output:', error.rawOutput);
|
|
307
396
|
} else {
|
|
308
397
|
throw error;
|
|
309
398
|
}
|
|
@@ -422,6 +422,86 @@ const sdk = new QodoSDK({
|
|
|
422
422
|
|
|
423
423
|
---
|
|
424
424
|
|
|
425
|
+
## Pipeline and Middleware Errors
|
|
426
|
+
|
|
427
|
+
### Pipeline Step Failed
|
|
428
|
+
|
|
429
|
+
**Error:**
|
|
430
|
+
```
|
|
431
|
+
PipelineExecutionError: Step "lint" failed: ...
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
**Cause:** A pipeline step threw an error and no error strategy was set.
|
|
435
|
+
|
|
436
|
+
**Solution:** Add error handling per step, or use gates to guard steps:
|
|
437
|
+
|
|
438
|
+
```typescript
|
|
439
|
+
sdkPipeline()
|
|
440
|
+
.step('lint', lintFn, { onError: 'skip' }) // Skip on failure
|
|
441
|
+
.gate((state) => !!state.lintOutput) // Gate: halt if no lint output
|
|
442
|
+
.step('review', reviewFn, {
|
|
443
|
+
onError: (error, state) => ({ fallback: true }), // Custom recovery
|
|
444
|
+
})
|
|
445
|
+
.build();
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
---
|
|
449
|
+
|
|
450
|
+
### Structured Output Validation Failed
|
|
451
|
+
|
|
452
|
+
**Error:**
|
|
453
|
+
```
|
|
454
|
+
QodoOutputValidationError: Structured output validation failed
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
**Cause:** The agent returned data that doesn't match the Zod output schema.
|
|
458
|
+
|
|
459
|
+
**Solution:** Check `error.issues` for details and `error.rawOutput` for what the agent actually returned:
|
|
460
|
+
|
|
461
|
+
```typescript
|
|
462
|
+
import { QodoOutputValidationError } from '@qodo/sdk';
|
|
463
|
+
|
|
464
|
+
try {
|
|
465
|
+
await sdk.run('analyze');
|
|
466
|
+
} catch (e) {
|
|
467
|
+
if (e instanceof QodoOutputValidationError) {
|
|
468
|
+
console.error('Issues:', e.issues); // [{ path: ['score'], message: '...' }]
|
|
469
|
+
console.error('Raw:', e.rawOutput); // What the agent returned
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
---
|
|
475
|
+
|
|
476
|
+
### Tool Middleware Error
|
|
477
|
+
|
|
478
|
+
**Error:**
|
|
479
|
+
```
|
|
480
|
+
ToolMiddlewareError: Middleware "my-middleware" failed in preExecute
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
**Cause:** A tool middleware hook threw or timed out (default: 10s).
|
|
484
|
+
|
|
485
|
+
**Solution:** Check the middleware implementation and handle errors gracefully:
|
|
486
|
+
|
|
487
|
+
```typescript
|
|
488
|
+
import { ToolMiddlewareError, MIDDLEWARE_TIMEOUT_MS } from '@qodo/sdk';
|
|
489
|
+
|
|
490
|
+
// Middleware hooks should be fast and defensive
|
|
491
|
+
const safeMiddleware = {
|
|
492
|
+
name: 'safe-mw',
|
|
493
|
+
preExecute(toolData) {
|
|
494
|
+
try {
|
|
495
|
+
// Your logic here
|
|
496
|
+
} catch {
|
|
497
|
+
// Don't throw — return void to pass through
|
|
498
|
+
}
|
|
499
|
+
},
|
|
500
|
+
};
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
---
|
|
504
|
+
|
|
425
505
|
## Quick Debugging Checklist
|
|
426
506
|
|
|
427
507
|
When something isn't working:
|
package/dist/api/agent.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../src/api/agent.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,YAAY,EAAC,MAAM,QAAQ,CAAC;AAGpC,OAAO,EAGL,YAAY,EAEb,MAAM,YAAY,CAAC;AAIpB,OAAO,EAAC,cAAc,EAAC,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAC,WAAW,EAAC,MAAM,mBAAmB,CAAC;AAK9C,OAAO,EAAkB,eAAe,EAAC,MAAM,gBAAgB,CAAC;AAuBhE,qBAAa,QAAS,SAAQ,YAAY;IAkC5B,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC;IAjC5C,OAAO,CAAC,QAAQ,CAAkB;IAElC,OAAO,CAAC,cAAc;IAQtB,OAAO,CAAC,KAAK;IAMb,OAAO,CAAC,cAAc,CAAC,CAAe;IACtC,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAsC;IAI1E,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAqB;IACvD,OAAO,CAAC,eAAe,CAAM;IAC7B,OAAO,CAAC,UAAU,CAAM;IACxB,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAa;IACzC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAc;IAC1C,OAAO,CAAC,kBAAkB,CAAsB;IAChD,OAAO,CAAC,cAAc,CAAS;IAI/B,OAAO,CAAC,wBAAwB,CAA8B;gBAEjC,cAAc,CAAC,EAAE,cAAc,YAAA;YAuB9C,eAAe;IAyB7B,OAAO,CAAC,sBAAsB;IAkF9B,OAAO,CAAC,qBAAqB;IAS7B,OAAO,CAAC,mBAAmB;IAQ3B,OAAO,CAAC,oBAAoB;IAKrB,kBAAkB,IAAI,eAAe;IAIrC,uBAAuB,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,GAAG,MAAM,IAAI;IAKtF,OAAO,CAAC,oBAAoB;YAUd,6BAA6B;IAkBpC,iBAAiB,CAAC,UAAU,EAAE,OAAO,GAAG,IAAI;IAgB5C,kBAAkB,IAAI,IAAI;IAK3B,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAwBxE,OAAO,CAAC,yBAAyB;IAUpB,wBAAwB,CAAC,UAAU,EAAE,MAAM,EAAE,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAmC1G,UAAU,CAAC,YAAY,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAarD,SAAS,CAAC,YAAY,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAmB7C,iBAAiB,CAAC,OAAO,GAAE,OAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAIvE,OAAO,CAAC,eAAe;YA4BT,cAAc;IAKrB,oBAAoB,IAAI,IAAI;IAInC,OAAO,CAAC,mBAAmB;IAY3B,OAAO,CAAC,sBAAsB;YAUhB,iBAAiB;YASjB,kBAAkB;YAWlB,aAAa;YAqEb,sBAAsB;YAStB,cAAc;YAsCd,uBAAuB;YA0CvB,kBAAkB;IA4ChC,OAAO,CAAC,mBAAmB;YAIb,gBAAgB;YAWhB,aAAa;YAab,mBAAmB;
|
|
1
|
+
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../src/api/agent.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,YAAY,EAAC,MAAM,QAAQ,CAAC;AAGpC,OAAO,EAGL,YAAY,EAEb,MAAM,YAAY,CAAC;AAIpB,OAAO,EAAC,cAAc,EAAC,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAC,WAAW,EAAC,MAAM,mBAAmB,CAAC;AAK9C,OAAO,EAAkB,eAAe,EAAC,MAAM,gBAAgB,CAAC;AAuBhE,qBAAa,QAAS,SAAQ,YAAY;IAkC5B,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC;IAjC5C,OAAO,CAAC,QAAQ,CAAkB;IAElC,OAAO,CAAC,cAAc;IAQtB,OAAO,CAAC,KAAK;IAMb,OAAO,CAAC,cAAc,CAAC,CAAe;IACtC,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAsC;IAI1E,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAqB;IACvD,OAAO,CAAC,eAAe,CAAM;IAC7B,OAAO,CAAC,UAAU,CAAM;IACxB,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAa;IACzC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAc;IAC1C,OAAO,CAAC,kBAAkB,CAAsB;IAChD,OAAO,CAAC,cAAc,CAAS;IAI/B,OAAO,CAAC,wBAAwB,CAA8B;gBAEjC,cAAc,CAAC,EAAE,cAAc,YAAA;YAuB9C,eAAe;IAyB7B,OAAO,CAAC,sBAAsB;IAkF9B,OAAO,CAAC,qBAAqB;IAS7B,OAAO,CAAC,mBAAmB;IAQ3B,OAAO,CAAC,oBAAoB;IAKrB,kBAAkB,IAAI,eAAe;IAIrC,uBAAuB,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,GAAG,MAAM,IAAI;IAKtF,OAAO,CAAC,oBAAoB;YAUd,6BAA6B;IAkBpC,iBAAiB,CAAC,UAAU,EAAE,OAAO,GAAG,IAAI;IAgB5C,kBAAkB,IAAI,IAAI;IAK3B,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAwBxE,OAAO,CAAC,yBAAyB;IAUpB,wBAAwB,CAAC,UAAU,EAAE,MAAM,EAAE,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAmC1G,UAAU,CAAC,YAAY,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAarD,SAAS,CAAC,YAAY,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAmB7C,iBAAiB,CAAC,OAAO,GAAE,OAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAIvE,OAAO,CAAC,eAAe;YA4BT,cAAc;IAKrB,oBAAoB,IAAI,IAAI;IAInC,OAAO,CAAC,mBAAmB;IAY3B,OAAO,CAAC,sBAAsB;YAUhB,iBAAiB;YASjB,kBAAkB;YAWlB,aAAa;YAqEb,sBAAsB;YAStB,cAAc;YAsCd,uBAAuB;YA0CvB,kBAAkB;IA4ChC,OAAO,CAAC,mBAAmB;YAIb,gBAAgB;YAWhB,aAAa;YAab,mBAAmB;YA0DnB,iBAAiB;YAajB,QAAQ;YAiGR,gBAAgB;IAmD9B,OAAO,CAAC,kBAAkB;YAwBZ,oBAAoB;YAgBpB,mBAAmB;YAUnB,WAAW;IAkClB,kBAAkB,IAAI,IAAI;IAK1B,OAAO,IAAI,IAAI;IAUf,cAAc,IAAI,WAAW;CAGrC"}
|
package/dist/api/agent.js
CHANGED
|
@@ -6,7 +6,7 @@ import { getUserData, getCurrentGitSha1 } from "./utils.js";
|
|
|
6
6
|
import { EndNode, UserResponse } from "../constants/tools.js";
|
|
7
7
|
import { SessionContext } from "../session/index.js";
|
|
8
8
|
import { TaskTracker } from "./taskTracking.js";
|
|
9
|
-
import {
|
|
9
|
+
import { ToolProcessorManager } from "../mcp/index.js";
|
|
10
10
|
import process from "node:process";
|
|
11
11
|
import { ServerData } from "../session/index.js";
|
|
12
12
|
import { httpRequest } from "./http.js";
|
|
@@ -166,7 +166,7 @@ export class AgentAPI extends EventEmitter {
|
|
|
166
166
|
await this.responseCallback({ forceStop: true });
|
|
167
167
|
}
|
|
168
168
|
}
|
|
169
|
-
catch { }
|
|
169
|
+
catch { /* best-effort: forceStop on reconnect should not crash the WS listener */ }
|
|
170
170
|
});
|
|
171
171
|
this.wsClient.on('checkpointRecovery', (info) => {
|
|
172
172
|
this.debug('[AgentAPI] Checkpoint recovery initiated', `| Reason: ${info.reason}`, info.checkpoint ? `| Checkpoint: ${info.checkpoint.substring(0, 8)}` : '');
|
|
@@ -639,10 +639,15 @@ export class AgentAPI extends EventEmitter {
|
|
|
639
639
|
return;
|
|
640
640
|
}
|
|
641
641
|
const isAutoApprovedTool = this.mcpManager.isAutoApprovedTool(toolData.server_name, toolData.tool, toolData.tool_args);
|
|
642
|
-
|
|
643
|
-
const processedToolData = await toolProcessorManager.preProcessTool(toolData, this.sessionContext);
|
|
642
|
+
const processedToolData = await ToolProcessorManager.getInstance().preProcessTool(toolData, this.sessionContext);
|
|
644
643
|
await this.processToolReasoning(processedToolData, isAutoApprovedTool);
|
|
645
|
-
|
|
644
|
+
// Dry run: simulate tool execution without side effects
|
|
645
|
+
if (this.sessionContext?.isDryRun()) {
|
|
646
|
+
const dryResult = await ToolProcessorManager.getInstance().dryRunTool(processedToolData, this.sessionContext);
|
|
647
|
+
await this.processToolResponse(processedToolData, dryResult);
|
|
648
|
+
await this.sendToolResponse(processedToolData, dryResult);
|
|
649
|
+
}
|
|
650
|
+
else if (isAutoApprovedTool) {
|
|
646
651
|
await this.callTool(processedToolData);
|
|
647
652
|
}
|
|
648
653
|
else {
|
|
@@ -701,7 +706,7 @@ export class AgentAPI extends EventEmitter {
|
|
|
701
706
|
}
|
|
702
707
|
}
|
|
703
708
|
}
|
|
704
|
-
catch { }
|
|
709
|
+
catch { /* best-effort: tool arg patching should not block tool execution */ }
|
|
705
710
|
if (!this.mcpManager) {
|
|
706
711
|
// Should not be reachable because we guard earlier, but keep a safe fallback
|
|
707
712
|
// that gracefully declines the tool call instead of throwing.
|
|
@@ -723,7 +728,7 @@ export class AgentAPI extends EventEmitter {
|
|
|
723
728
|
return;
|
|
724
729
|
}
|
|
725
730
|
// Post-process the tool result
|
|
726
|
-
const processedResponse = await
|
|
731
|
+
const processedResponse = await ToolProcessorManager.getInstance().postProcessTool(toolData, response);
|
|
727
732
|
await this.processToolResponse(toolData, processedResponse);
|
|
728
733
|
// Send tool response via WebSocket
|
|
729
734
|
await this.sendToolResponse(toolData, processedResponse);
|
|
@@ -870,7 +875,7 @@ export class AgentAPI extends EventEmitter {
|
|
|
870
875
|
try {
|
|
871
876
|
this.cleanupConnections();
|
|
872
877
|
}
|
|
873
|
-
catch { }
|
|
878
|
+
catch { /* cleanup: connection teardown must not throw */ }
|
|
874
879
|
this.pendingToolRequests.clear();
|
|
875
880
|
this.currentSession = undefined;
|
|
876
881
|
this.latestSessionId = "";
|