@vinhnt-sdk/step-executor 0.1.3

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.
Files changed (67) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +29 -0
  3. package/dist/approval-handler.d.ts +18 -0
  4. package/dist/approval-handler.d.ts.map +1 -0
  5. package/dist/approval-handler.js +39 -0
  6. package/dist/approval-handler.js.map +1 -0
  7. package/dist/circuit-breaker.d.ts +48 -0
  8. package/dist/circuit-breaker.d.ts.map +1 -0
  9. package/dist/circuit-breaker.js +171 -0
  10. package/dist/circuit-breaker.js.map +1 -0
  11. package/dist/hooks.d.ts +15 -0
  12. package/dist/hooks.d.ts.map +1 -0
  13. package/dist/hooks.js +2 -0
  14. package/dist/hooks.js.map +1 -0
  15. package/dist/index.d.ts +22 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.js +22 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/kernel-error.d.ts +10 -0
  20. package/dist/kernel-error.d.ts.map +1 -0
  21. package/dist/kernel-error.js +12 -0
  22. package/dist/kernel-error.js.map +1 -0
  23. package/dist/kernel-utils.d.ts +49 -0
  24. package/dist/kernel-utils.d.ts.map +1 -0
  25. package/dist/kernel-utils.js +117 -0
  26. package/dist/kernel-utils.js.map +1 -0
  27. package/dist/path-policy.d.ts +18 -0
  28. package/dist/path-policy.d.ts.map +1 -0
  29. package/dist/path-policy.js +38 -0
  30. package/dist/path-policy.js.map +1 -0
  31. package/dist/permission-gate.d.ts +93 -0
  32. package/dist/permission-gate.d.ts.map +1 -0
  33. package/dist/permission-gate.js +303 -0
  34. package/dist/permission-gate.js.map +1 -0
  35. package/dist/run-context.d.ts +26 -0
  36. package/dist/run-context.d.ts.map +1 -0
  37. package/dist/run-context.js +13 -0
  38. package/dist/run-context.js.map +1 -0
  39. package/dist/run-state.d.ts +27 -0
  40. package/dist/run-state.d.ts.map +1 -0
  41. package/dist/run-state.js +88 -0
  42. package/dist/run-state.js.map +1 -0
  43. package/dist/self-correction.d.ts +29 -0
  44. package/dist/self-correction.d.ts.map +1 -0
  45. package/dist/self-correction.js +89 -0
  46. package/dist/self-correction.js.map +1 -0
  47. package/dist/step-executor.d.ts +81 -0
  48. package/dist/step-executor.d.ts.map +1 -0
  49. package/dist/step-executor.js +314 -0
  50. package/dist/step-executor.js.map +1 -0
  51. package/dist/termination.d.ts +87 -0
  52. package/dist/termination.d.ts.map +1 -0
  53. package/dist/termination.js +89 -0
  54. package/dist/termination.js.map +1 -0
  55. package/dist/tool-context-builder.d.ts +22 -0
  56. package/dist/tool-context-builder.d.ts.map +1 -0
  57. package/dist/tool-context-builder.js +42 -0
  58. package/dist/tool-context-builder.js.map +1 -0
  59. package/dist/tool-error-router.d.ts +26 -0
  60. package/dist/tool-error-router.d.ts.map +1 -0
  61. package/dist/tool-error-router.js +85 -0
  62. package/dist/tool-error-router.js.map +1 -0
  63. package/dist/tool-result-processor.d.ts +24 -0
  64. package/dist/tool-result-processor.d.ts.map +1 -0
  65. package/dist/tool-result-processor.js +47 -0
  66. package/dist/tool-result-processor.js.map +1 -0
  67. package/package.json +63 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Nguyen Thanh Vinh
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # @vinhnt-sdk/step-executor
2
+
3
+ Step execution kernel for VNT Agent — tool lifecycle, per-tool timeouts, permission gating, doom-loop detection, self-correction and run state machine.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ pnpm add @vinhnt-sdk/step-executor
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```ts
14
+ import { StepExecutor, PermissionGate, runLoop, RunStateMachine } from "@vinhnt-sdk/step-executor";
15
+ ```
16
+
17
+ ## Contents
18
+
19
+ - `StepExecutor` — per-step tool execution: invoke → permission re-check → run with timeout → result processing, with pluggable hooks/logging
20
+ - `PermissionGate` — permission evaluation against saved patterns, rules and risk defaults (consumes `@vinhnt-sdk/permission`)
21
+ - `tool-context-builder` / `approval-handler` / `tool-error-router` / `self-correction` / `tool-result-processor` — step lifecycle helpers
22
+ - `termination` — stop-condition evaluation and judge-based loop termination
23
+ - `kernel-utils` — doom-loop detection, arg hashing, timeouts, tool domains, defaults
24
+ - `run-state` / `run-context` — per-run state machine and context
25
+ - `circuit-breaker` / `kernel-error` — failure isolation and typed errors
26
+
27
+ ## Hooks
28
+
29
+ The package exposes a minimal structural `StepExecutorPluginHooks` interface. Hosts (e.g. core's `PluginManager`) only need to implement `fireHook` for the tool-lifecycle / permission hook names.
@@ -0,0 +1,18 @@
1
+ import type { RunId, RequestContext } from "@vinhnt-sdk/schema";
2
+ import type { ChatMessage } from "@vinhnt-sdk/schema";
3
+ import type { ToolContext } from "@vinhnt-sdk/tools";
4
+ import type { StepExecutorPluginHooks } from "./hooks.js";
5
+ import type { PermissionGate, PermissionCheckResult } from "./permission-gate.js";
6
+ import type { ToolExecutionPlan } from "./step-executor.js";
7
+ import type { AgentConfig } from "@vinhnt-sdk/schema";
8
+ /** Dependencies required by {@link handleApproval}. */
9
+ export interface ApprovalHandlerDeps {
10
+ readonly store: {
11
+ emitEvent(event: Omit<import("@vinhnt-sdk/schema").KnownRunEvent, "sequence">, persist?: boolean): Promise<void>;
12
+ };
13
+ readonly permissionGate: PermissionGate;
14
+ readonly pluginManager: StepExecutorPluginHooks | undefined;
15
+ currentAgent: AgentConfig | undefined;
16
+ }
17
+ export declare function handleApproval(permResult: PermissionCheckResult, tc: ToolExecutionPlan, toolCtx: ToolContext, runId: RunId, ctx: RequestContext, _sessionId: string | undefined, messages: ChatMessage[], deps: ApprovalHandlerDeps, selfApproving?: boolean): Promise<boolean>;
18
+ //# sourceMappingURL=approval-handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"approval-handler.d.ts","sourceRoot":"","sources":["../src/approval-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAChE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAC1D,OAAO,KAAK,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAClF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAGtD,uDAAuD;AACvD,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,KAAK,EAAE;QAAE,SAAS,CAAC,KAAK,EAAE,IAAI,CAAC,OAAO,oBAAoB,EAAE,aAAa,EAAE,UAAU,CAAC,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;KAAE,CAAC;IACrI,QAAQ,CAAC,cAAc,EAAE,cAAc,CAAC;IACxC,QAAQ,CAAC,aAAa,EAAE,uBAAuB,GAAG,SAAS,CAAC;IAC5D,YAAY,EAAE,WAAW,GAAG,SAAS,CAAC;CACvC;AAED,wBAAsB,cAAc,CAClC,UAAU,EAAE,qBAAqB,EACjC,EAAE,EAAE,iBAAiB,EACrB,OAAO,EAAE,WAAW,EACpB,KAAK,EAAE,KAAK,EACZ,GAAG,EAAE,cAAc,EACnB,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,QAAQ,EAAE,WAAW,EAAE,EACvB,IAAI,EAAE,mBAAmB,EACzB,aAAa,CAAC,EAAE,OAAO,GACtB,OAAO,CAAC,OAAO,CAAC,CAsClB"}
@@ -0,0 +1,39 @@
1
+ import { toolDomain } from "./kernel-utils.js";
2
+ export async function handleApproval(permResult, tc, toolCtx, runId, ctx, _sessionId, messages, deps, selfApproving) {
3
+ // Allowed or needs-approval → proceed. A hard deny (!allowed, no approval
4
+ // needed) must surface as a rejection — a caller who skips this check would
5
+ // otherwise hand a denied tool straight through to execution.
6
+ if (permResult.allowed)
7
+ return true;
8
+ if (!permResult.needsApproval) {
9
+ messages.push({ role: "tool", toolCallId: tc.toolId, content: `Error: Tool "${tc.toolName}" denied by permission rules` });
10
+ return false;
11
+ }
12
+ // Single approval path: self-approving tools ask via their own `ctx.ask`
13
+ // (which persists savePatterns on "always"). Defer the gate-level ask.
14
+ if (selfApproving)
15
+ return true;
16
+ const savedOk = deps.permissionGate.checkSavedApproval(tc.toolName, tc.args, deps.currentAgent?.id);
17
+ if (savedOk)
18
+ return true;
19
+ const reply = await toolCtx.ask({
20
+ permission: `tool.${tc.toolName}`,
21
+ resource: tc.toolName,
22
+ reason: permResult.reason,
23
+ });
24
+ if (reply === "reject") {
25
+ deps.permissionGate.saveRejection(tc.toolName, tc.args, deps.currentAgent?.id);
26
+ await deps.store.emitEvent({
27
+ id: crypto.randomUUID(), runId, type: "tool.failed",
28
+ occurredAt: new Date().toISOString(), traceId: ctx.traceId,
29
+ data: { toolId: tc.toolId, toolName: tc.toolName, domain: toolDomain(tc.toolName), decision: "deny", error: `Tool "${tc.toolName}" rejected by user` },
30
+ });
31
+ messages.push({ role: "tool", toolCallId: tc.toolId, content: `Error: Tool "${tc.toolName}" rejected by user` });
32
+ return false;
33
+ }
34
+ if (reply === "always") {
35
+ deps.permissionGate.saveApproval(tc.toolName, tc.args, deps.currentAgent?.id);
36
+ }
37
+ return true;
38
+ }
39
+ //# sourceMappingURL=approval-handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"approval-handler.js","sourceRoot":"","sources":["../src/approval-handler.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAU/C,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,UAAiC,EACjC,EAAqB,EACrB,OAAoB,EACpB,KAAY,EACZ,GAAmB,EACnB,UAA8B,EAC9B,QAAuB,EACvB,IAAyB,EACzB,aAAuB;IAEvB,0EAA0E;IAC1E,4EAA4E;IAC5E,8DAA8D;IAC9D,IAAI,UAAU,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IACpC,IAAI,CAAC,UAAU,CAAC,aAAa,EAAE,CAAC;QAC9B,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,gBAAgB,EAAE,CAAC,QAAQ,8BAA8B,EAAE,CAAC,CAAC;QAC3H,OAAO,KAAK,CAAC;IACf,CAAC;IAED,yEAAyE;IACzE,uEAAuE;IACvE,IAAI,aAAa;QAAE,OAAO,IAAI,CAAC;IAE/B,MAAM,OAAO,GAAG,IAAI,CAAC,cAAc,CAAC,kBAAkB,CAAC,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,IAA+B,EAAE,IAAI,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;IAC/H,IAAI,OAAO;QAAE,OAAO,IAAI,CAAC;IAEzB,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QAC9B,UAAU,EAAE,QAAQ,EAAE,CAAC,QAAQ,EAAE;QACjC,QAAQ,EAAE,EAAE,CAAC,QAAQ;QACrB,MAAM,EAAE,UAAU,CAAC,MAAO;KAC3B,CAAC,CAAC;IAEH,IAAI,KAAK,KAAK,QAAQ,EAAE,CAAC;QACvB,IAAI,CAAC,cAAc,CAAC,aAAa,CAAC,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,IAA+B,EAAE,IAAI,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;QAC1G,MAAM,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC;YACzB,EAAE,EAAE,MAAM,CAAC,UAAU,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,aAAa;YACnD,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO;YAC1D,IAAI,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,QAAQ,oBAAoB,EAAE;SACvJ,CAAC,CAAC;QACH,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,gBAAgB,EAAE,CAAC,QAAQ,oBAAoB,EAAE,CAAC,CAAC;QACjH,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,KAAK,KAAK,QAAQ,EAAE,CAAC;QACvB,IAAI,CAAC,cAAc,CAAC,YAAY,CAAC,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,IAA+B,EAAE,IAAI,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;IAC3G,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,48 @@
1
+ /** Current circuit breaker state. */
2
+ export type CircuitState = "closed" | "open" | "half_open";
3
+ /** Tuning for {@link CircuitBreaker}: failure/success thresholds and retry policy. */
4
+ export interface CircuitBreakerOptions {
5
+ failureThreshold?: number;
6
+ successThreshold?: number;
7
+ resetTimeoutMs?: number;
8
+ isFailure?: (err: unknown) => boolean;
9
+ /** Maximum number of retries for transient failures. Default: 3 */
10
+ maxRetries?: number;
11
+ /** Base delay for exponential backoff in ms. Default: 1000 */
12
+ backoffMs?: number;
13
+ /** Maximum delay for backoff in ms. Default: 30000 */
14
+ maxBackoffMs?: number;
15
+ }
16
+ /** Circuit breaker with failure thresholds, retry/backoff and half-open probing. */
17
+ export declare class CircuitBreaker {
18
+ private state;
19
+ private failureCount;
20
+ private lastFailureTime;
21
+ private halfOpenSuccesses;
22
+ private readonly options;
23
+ constructor(options?: CircuitBreakerOptions);
24
+ getState(): CircuitState;
25
+ /**
26
+ * Execute a function with circuit breaker and retry logic.
27
+ * Retries on transient failures with exponential backoff.
28
+ *
29
+ * @param fn - The async function to execute
30
+ * @param signal - Optional AbortSignal for cancellation
31
+ * @returns The result of the function
32
+ * @throws CircuitBreakerOpenError if circuit is open
33
+ * @throws The original error if all retries fail
34
+ */
35
+ call<T>(fn: () => Promise<T>, signal?: AbortSignal): Promise<T>;
36
+ private sleepAbortable;
37
+ private onSuccess;
38
+ private onFailure;
39
+ reset(): void;
40
+ /** Get the current configuration options. */
41
+ getOptions(): Readonly<Required<CircuitBreakerOptions>>;
42
+ }
43
+ /** Thrown when a call is rejected because the breaker is open. */
44
+ export declare class CircuitBreakerOpenError extends Error {
45
+ readonly remainingMs: number;
46
+ constructor(resetTimeoutMs: number);
47
+ }
48
+ //# sourceMappingURL=circuit-breaker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"circuit-breaker.d.ts","sourceRoot":"","sources":["../src/circuit-breaker.ts"],"names":[],"mappings":"AAEA,qCAAqC;AACrC,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,MAAM,GAAG,WAAW,CAAC;AAE3D,sFAAsF;AACtF,MAAM,WAAW,qBAAqB;IACpC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC;IACtC,mEAAmE;IACnE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,8DAA8D;IAC9D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sDAAsD;IACtD,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAyBD,oFAAoF;AACpF,qBAAa,cAAc;IACzB,OAAO,CAAC,KAAK,CAA0B;IACvC,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,eAAe,CAAK;IAC5B,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAkC;gBAE9C,OAAO,CAAC,EAAE,qBAAqB;IAO3C,QAAQ,IAAI,YAAY;IAQxB;;;;;;;;;OASG;IACG,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,CAAC,CAAC;YA0DvD,cAAc;IAsB5B,OAAO,CAAC,SAAS;IAajB,OAAO,CAAC,SAAS;IAcjB,KAAK,IAAI,IAAI;IAOb,6CAA6C;IAC7C,UAAU,IAAI,QAAQ,CAAC,QAAQ,CAAC,qBAAqB,CAAC,CAAC;CAGxD;AAED,kEAAkE;AAClE,qBAAa,uBAAwB,SAAQ,KAAK;IAChD,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;gBAEjB,cAAc,EAAE,MAAM;CAKnC"}
@@ -0,0 +1,171 @@
1
+ import { VntError } from "@vinhnt-sdk/schema";
2
+ const DEFAULT_OPTIONS = {
3
+ failureThreshold: 5,
4
+ successThreshold: 2,
5
+ resetTimeoutMs: 30_000,
6
+ maxRetries: 3,
7
+ backoffMs: 1000,
8
+ maxBackoffMs: 30_000,
9
+ isFailure: (err) => {
10
+ if (err instanceof DOMException && err.name === "AbortError")
11
+ return false;
12
+ if (err instanceof Error && err.name === "AbortError")
13
+ return false;
14
+ // Structured SDK errors carry an explicit retryable flag — upstream auth
15
+ // (401/403) and validation failures are marked non-retryable and must never
16
+ // count toward the breaker or be retried, even if their message text does
17
+ // not match the substring heuristics below.
18
+ if (err instanceof VntError && err.retryable === false)
19
+ return false;
20
+ const msg = err instanceof Error ? err.message.toLowerCase() : String(err).toLowerCase();
21
+ if (msg.includes("auth") || msg.includes("unauthorized") || msg.includes("invalid api key"))
22
+ return false;
23
+ if (msg.includes("context") && msg.includes("token"))
24
+ return false;
25
+ if (msg.includes("not found") || msg.includes("not_found"))
26
+ return false;
27
+ return true;
28
+ },
29
+ };
30
+ /** Circuit breaker with failure thresholds, retry/backoff and half-open probing. */
31
+ export class CircuitBreaker {
32
+ state = "closed";
33
+ failureCount = 0;
34
+ lastFailureTime = 0;
35
+ halfOpenSuccesses = 0;
36
+ options;
37
+ constructor(options) {
38
+ this.options = {
39
+ ...DEFAULT_OPTIONS,
40
+ ...Object.fromEntries(Object.entries(options ?? {}).filter(([, v]) => v !== undefined)),
41
+ };
42
+ }
43
+ getState() {
44
+ if (this.state === "open" && Date.now() - this.lastFailureTime >= this.options.resetTimeoutMs) {
45
+ this.state = "half_open";
46
+ this.halfOpenSuccesses = 0;
47
+ }
48
+ return this.state;
49
+ }
50
+ /**
51
+ * Execute a function with circuit breaker and retry logic.
52
+ * Retries on transient failures with exponential backoff.
53
+ *
54
+ * @param fn - The async function to execute
55
+ * @param signal - Optional AbortSignal for cancellation
56
+ * @returns The result of the function
57
+ * @throws CircuitBreakerOpenError if circuit is open
58
+ * @throws The original error if all retries fail
59
+ */
60
+ async call(fn, signal) {
61
+ const state = this.getState();
62
+ if (state === "open") {
63
+ throw new CircuitBreakerOpenError(this.options.resetTimeoutMs);
64
+ }
65
+ let lastError;
66
+ let attempt = 0;
67
+ while (attempt <= this.options.maxRetries) {
68
+ if (signal?.aborted) {
69
+ throw new DOMException("Aborted", "AbortError");
70
+ }
71
+ try {
72
+ const result = await fn();
73
+ this.onSuccess();
74
+ return result;
75
+ }
76
+ catch (err) {
77
+ lastError = err;
78
+ // Cancellation is never a failure — rethrow without counting it so an
79
+ // aborted run cannot trip the breaker or get retried.
80
+ if (signal?.aborted || (err instanceof DOMException && err.name === "AbortError") || (err instanceof Error && err.name === "AbortError")) {
81
+ throw signal?.aborted ? new DOMException("Aborted", "AbortError") : err;
82
+ }
83
+ // Check if error is retryable
84
+ if (!this.options.isFailure(err)) {
85
+ throw err;
86
+ }
87
+ this.onFailure(err);
88
+ // Don't retry if we've hit the circuit breaker
89
+ if (this.getState() === "open") {
90
+ throw new CircuitBreakerOpenError(this.options.resetTimeoutMs);
91
+ }
92
+ // Don't retry on last attempt
93
+ if (attempt >= this.options.maxRetries) {
94
+ throw err;
95
+ }
96
+ // Calculate delay with exponential backoff
97
+ const delay = Math.min(this.options.backoffMs * Math.pow(2, attempt), this.options.maxBackoffMs);
98
+ await this.sleepAbortable(delay, signal);
99
+ attempt++;
100
+ }
101
+ }
102
+ throw lastError;
103
+ }
104
+ async sleepAbortable(ms, signal) {
105
+ if (!signal) {
106
+ await new Promise((resolve) => setTimeout(resolve, ms));
107
+ return;
108
+ }
109
+ await new Promise((resolve, reject) => {
110
+ const timer = setTimeout(() => {
111
+ signal.removeEventListener("abort", onAbort);
112
+ resolve();
113
+ }, ms);
114
+ const onAbort = () => {
115
+ clearTimeout(timer);
116
+ reject(new DOMException("Aborted", "AbortError"));
117
+ };
118
+ signal.addEventListener("abort", onAbort, { once: true });
119
+ if (signal.aborted) {
120
+ clearTimeout(timer);
121
+ reject(new DOMException("Aborted", "AbortError"));
122
+ }
123
+ });
124
+ }
125
+ onSuccess() {
126
+ if (this.state === "half_open") {
127
+ this.halfOpenSuccesses++;
128
+ if (this.halfOpenSuccesses >= this.options.successThreshold) {
129
+ this.state = "closed";
130
+ this.failureCount = 0;
131
+ this.halfOpenSuccesses = 0;
132
+ }
133
+ }
134
+ else if (this.state === "closed") {
135
+ this.failureCount = 0;
136
+ }
137
+ }
138
+ onFailure(err) {
139
+ if (!this.options.isFailure(err))
140
+ return;
141
+ this.failureCount++;
142
+ this.lastFailureTime = Date.now();
143
+ if (this.failureCount >= this.options.failureThreshold) {
144
+ this.state = "open";
145
+ }
146
+ else if (this.state === "half_open") {
147
+ this.state = "open";
148
+ this.halfOpenSuccesses = 0;
149
+ }
150
+ }
151
+ reset() {
152
+ this.state = "closed";
153
+ this.failureCount = 0;
154
+ this.lastFailureTime = 0;
155
+ this.halfOpenSuccesses = 0;
156
+ }
157
+ /** Get the current configuration options. */
158
+ getOptions() {
159
+ return this.options;
160
+ }
161
+ }
162
+ /** Thrown when a call is rejected because the breaker is open. */
163
+ export class CircuitBreakerOpenError extends Error {
164
+ remainingMs;
165
+ constructor(resetTimeoutMs) {
166
+ super(`Circuit breaker is open — too many consecutive failures. Will retry in ${resetTimeoutMs}ms`);
167
+ this.name = "CircuitBreakerOpenError";
168
+ this.remainingMs = resetTimeoutMs;
169
+ }
170
+ }
171
+ //# sourceMappingURL=circuit-breaker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"circuit-breaker.js","sourceRoot":"","sources":["../src/circuit-breaker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Minimal structural plugin-hook surface used by the step executor.
3
+ *
4
+ * Hosts (e.g. core's `PluginManager`) only need to implement `fireHook` for
5
+ * the tool-lifecycle / permission hook names; no direct dependency on the
6
+ * full plugin contract.
7
+ */
8
+ export interface StepExecutorPluginHooks {
9
+ fireHook(name: "onToolInvoked" | "onBeforeToolExecution" | "onAfterToolExecution" | "onToolCompleted" | "onToolFailed" | "onShellEnv" | "onPermissionAsk", data: Record<string, unknown>): Promise<{
10
+ modified: Record<string, unknown>;
11
+ } | null | void> | {
12
+ modified: Record<string, unknown>;
13
+ } | null | void;
14
+ }
15
+ //# sourceMappingURL=hooks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CACN,IAAI,EACA,eAAe,GACf,uBAAuB,GACvB,sBAAsB,GACtB,iBAAiB,GACjB,cAAc,GACd,YAAY,GACZ,iBAAiB,EACrB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAE3B,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,GAAG,IAAI,GAAG,IAAI,CAAC,GAC5D;QAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,GACrC,IAAI,GACJ,IAAI,CAAC;CACV"}
package/dist/hooks.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=hooks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hooks.js","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":""}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * @module @vinhnt-sdk/step-executor
3
+ * Step execution kernel: tool lifecycle, per-tool timeouts, permission gating,
4
+ * doom-loop detection, self-correction and run state machine.
5
+ */
6
+ export type { StepExecutorPluginHooks } from "./hooks.js";
7
+ export { StepExecutor } from "./step-executor.js";
8
+ export type { StepExecutorDeps, ToolExecutionPlan } from "./step-executor.js";
9
+ export { DEFAULT_MAX_STEPS, DEFAULT_MAX_TOOL_CALLS_PER_STEP, DOOM_LOOP_THRESHOLD, toolDomain, } from "./kernel-utils.js";
10
+ export { evaluateStopConditions, buildJudgeMessages, parseJudgeVerdict, toToolCallOutcome } from "./termination.js";
11
+ export type { ToolCallOutcome, StepVerificationContext, StopCondition, TerminationPolicy } from "./termination.js";
12
+ export { PermissionGate } from "./permission-gate.js";
13
+ export type { ApprovalDecision, DynamicRule, PermissionCheckResult } from "./permission-gate.js";
14
+ export { createRunContext } from "./run-context.js";
15
+ export type { RunContext } from "./run-context.js";
16
+ export { KernelError } from "./kernel-error.js";
17
+ export type { KernelErrorCode } from "./kernel-error.js";
18
+ export { CircuitBreaker, CircuitBreakerOpenError } from "./circuit-breaker.js";
19
+ export type { CircuitState, CircuitBreakerOptions } from "./circuit-breaker.js";
20
+ export { RunStateMachine } from "./run-state.js";
21
+ export type { RunState } from "./run-state.js";
22
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,YAAY,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAI1D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,YAAY,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAI9E,OAAO,EACL,iBAAiB,EACjB,+BAA+B,EAC/B,mBAAmB,EACnB,UAAU,GACX,MAAM,mBAAmB,CAAC;AAI3B,OAAO,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACpH,YAAY,EAAE,eAAe,EAAE,uBAAuB,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAInH,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,YAAY,EAAE,gBAAgB,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAIjG,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,YAAY,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAInD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,YAAY,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAIzD,OAAO,EAAE,cAAc,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAC/E,YAAY,EAAE,YAAY,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAIhF,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,YAAY,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,22 @@
1
+ /**
2
+ * @module @vinhnt-sdk/step-executor
3
+ * Step execution kernel: tool lifecycle, per-tool timeouts, permission gating,
4
+ * doom-loop detection, self-correction and run state machine.
5
+ */
6
+ // === Step Executor ===
7
+ export { StepExecutor } from "./step-executor.js";
8
+ // === Kernel Utils (public subset) ===
9
+ export { DEFAULT_MAX_STEPS, DEFAULT_MAX_TOOL_CALLS_PER_STEP, DOOM_LOOP_THRESHOLD, toolDomain, } from "./kernel-utils.js";
10
+ // === Termination ===
11
+ export { evaluateStopConditions, buildJudgeMessages, parseJudgeVerdict, toToolCallOutcome } from "./termination.js";
12
+ // === Permission Gate ===
13
+ export { PermissionGate } from "./permission-gate.js";
14
+ // === Run Context ===
15
+ export { createRunContext } from "./run-context.js";
16
+ // === Kernel Error ===
17
+ export { KernelError } from "./kernel-error.js";
18
+ // === Circuit Breaker ===
19
+ export { CircuitBreaker, CircuitBreakerOpenError } from "./circuit-breaker.js";
20
+ // === Run State ===
21
+ export { RunStateMachine } from "./run-state.js";
22
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,wBAAwB;AAExB,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAGlD,uCAAuC;AAEvC,OAAO,EACL,iBAAiB,EACjB,+BAA+B,EAC/B,mBAAmB,EACnB,UAAU,GACX,MAAM,mBAAmB,CAAC;AAE3B,sBAAsB;AAEtB,OAAO,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAGpH,0BAA0B;AAE1B,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAGtD,sBAAsB;AAEtB,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAGpD,uBAAuB;AAEvB,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGhD,0BAA0B;AAE1B,OAAO,EAAE,cAAc,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAG/E,oBAAoB;AAEpB,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,10 @@
1
+ import { VntError } from "@vinhnt-sdk/schema";
2
+ /** Kernel-level failure codes for {@link KernelError}. */
3
+ export type KernelErrorCode = "session_busy" | "cancelled" | "max_steps_exceeded" | "max_tokens_exceeded" | "tool_failed" | "model_failed" | "session_store_failed" | "internal_error" | "timeout" | "model_unavailable";
4
+ /** Kernel-level failure with a typed {@link KernelErrorCode}. */
5
+ export declare class KernelError extends VntError {
6
+ readonly code: string;
7
+ readonly retryable = false;
8
+ constructor(kernelCode: KernelErrorCode, message: string, cause?: unknown);
9
+ }
10
+ //# sourceMappingURL=kernel-error.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kernel-error.d.ts","sourceRoot":"","sources":["../src/kernel-error.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAE9C,0DAA0D;AAC1D,MAAM,MAAM,eAAe,GACvB,cAAc,GACd,WAAW,GACX,oBAAoB,GACpB,qBAAqB,GACrB,aAAa,GACb,cAAc,GACd,sBAAsB,GACtB,gBAAgB,GAChB,SAAS,GACT,mBAAmB,CAAC;AAExB,iEAAiE;AACjE,qBAAa,WAAY,SAAQ,QAAQ;IACvC,SAAyB,IAAI,EAAE,MAAM,CAAC;IACtC,SAAyB,SAAS,SAAS;gBAE/B,UAAU,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO;CAK1E"}
@@ -0,0 +1,12 @@
1
+ import { VntError } from "@vinhnt-sdk/schema";
2
+ /** Kernel-level failure with a typed {@link KernelErrorCode}. */
3
+ export class KernelError extends VntError {
4
+ code;
5
+ retryable = false;
6
+ constructor(kernelCode, message, cause) {
7
+ super(message, { cause });
8
+ this.code = kernelCode;
9
+ this.name = `KernelError.${kernelCode}`;
10
+ }
11
+ }
12
+ //# sourceMappingURL=kernel-error.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kernel-error.js","sourceRoot":"","sources":["../src/kernel-error.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAe9C,iEAAiE;AACjE,MAAM,OAAO,WAAY,SAAQ,QAAQ;IACd,IAAI,CAAS;IACb,SAAS,GAAG,KAAK,CAAC;IAE3C,YAAY,UAA2B,EAAE,OAAe,EAAE,KAAe;QACvE,KAAK,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;QAC1B,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;QACvB,IAAI,CAAC,IAAI,GAAG,eAAe,UAAU,EAAE,CAAC;IAC1C,CAAC;CACF"}
@@ -0,0 +1,49 @@
1
+ import type { RunId } from "@vinhnt-sdk/schema";
2
+ /** Race a promise against an abort signal — rejects with RunAbortedError if aborted. @internal */
3
+ export declare function raceWithAbort<T>(promise: Promise<T>, signal: AbortSignal, runId: RunId): Promise<T>;
4
+ /**
5
+ * Run a tool execution with a cooperative timeout (RV-19). The caller's
6
+ * `run` receives a local `AbortSignal` that fires when EITHER the parent
7
+ * (run) signal aborts OR the tool exceeds `timeoutMs`. Well-behaved tools
8
+ * that watch their context signal stop their side effects at the deadline
9
+ * instead of continuing past it (a plain `Promise.race` abandons the tool
10
+ * promise and its effects keep running). The returned promise still
11
+ * hard-rejects at `timeoutMs`, so a non-cooperative tool can never hang the
12
+ * caller longer than the deadline. Parent aborts are NOT synthesised here —
13
+ * the caller's `raceWithAbort` rejects with `RunAbortedError`.
14
+ * @internal
15
+ */
16
+ export declare function withToolTimeout<T>(run: (signal: AbortSignal) => Promise<T>, timeoutMs: number, parent: AbortSignal, timeoutMessage: string): Promise<T>;
17
+ /** Default cap on steps per run. */
18
+ export declare const DEFAULT_MAX_STEPS = 25;
19
+ /** Default cap on tool calls per step. */
20
+ export declare const DEFAULT_MAX_TOOL_CALLS_PER_STEP = 20;
21
+ /** Consecutive identical calls that trigger doom-loop detection. */
22
+ export declare const DOOM_LOOP_THRESHOLD = 3;
23
+ /** System prompt guiding the model to correct a failed tool call. @internal */
24
+ export declare const SELF_CORRECT_PROMPT = "A tool call just failed. Analyze the error and try a corrected approach.\n\nGuidelines:\n- If the error is about arguments, fix the arguments and retry.\n- If the tool is unavailable, suggest an alternative tool.\n- If the problem is permanent (e.g., invalid request), explain to the user.\n- Do NOT repeat the same failing call.";
25
+ /** A recorded tool invocation used for doom-loop detection. @internal */
26
+ export interface RecentCall {
27
+ id: string;
28
+ args: unknown;
29
+ /** Canonical hash of `args` — precomputed once for O(1) doom-loop comparison */
30
+ argsKey?: string;
31
+ }
32
+ /**
33
+ * Stable, order-independent hash of an arbitrary tool-arguments value.
34
+ * Object key order is normalized so `{a:1,b:2}` and `{b:2,a:1}` hash the same,
35
+ * and the hash is computed once per call (vs. repeated JSON.stringify in a
36
+ * doom-loop scan). Collisions are possible but astronomically unlikely for the
37
+ * small arg payloads agents produce.
38
+ * @internal
39
+ */
40
+ export declare function hashArgs(value: unknown): string;
41
+ /** Detect whether the same tool+args repeated the last `threshold` calls. @internal */
42
+ export declare function detectDoomLoop(recentCalls: RecentCall[], name: string, args: unknown, threshold?: number): boolean;
43
+ /**
44
+ * Derive the owning domain from a namespaced tool id:
45
+ * `mcp__<server>__<tool>` → "mcp:<server>", `coding.read_file` → "coding",
46
+ * bare ids → "core".
47
+ */
48
+ export declare function toolDomain(toolName: string): string;
49
+ //# sourceMappingURL=kernel-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kernel-utils.d.ts","sourceRoot":"","sources":["../src/kernel-utils.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAEhD,kGAAkG;AAClG,wBAAgB,aAAa,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,CAAC,CAAC,CAanG;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAC/B,GAAG,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC,EACxC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,WAAW,EACnB,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC,CAAC,CAAC,CA4BZ;AAED,oCAAoC;AACpC,eAAO,MAAM,iBAAiB,KAAK,CAAC;AACpC,0CAA0C;AAC1C,eAAO,MAAM,+BAA+B,KAAK,CAAC;AAClD,oEAAoE;AACpE,eAAO,MAAM,mBAAmB,IAAI,CAAC;AAErC,+EAA+E;AAC/E,eAAO,MAAM,mBAAmB,8UAMO,CAAC;AAExC,yEAAyE;AACzE,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,OAAO,CAAC;IACd,gFAAgF;IAChF,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAE/C;AAoBD,uFAAuF;AACvF,wBAAgB,cAAc,CAAC,WAAW,EAAE,UAAU,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,SAAsB,GAAG,OAAO,CAK/H;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAOnD"}