@agent-api/sdk 1.4.2 → 1.4.4

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/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog — @agent-api/sdk
2
2
 
3
+ ## 1.4.4
4
+
5
+ ### Added
6
+
7
+ - Added a model-facing `local_pause` tool primitive for bounded local workflow waits, with early-resume hooks for host runtimes.
8
+
9
+ ## 1.4.3
10
+
11
+ ### Fixed
12
+
13
+ - Made successful `local_workdir.apply_edits` results compact by keeping rollback backups internal and reporting changed files plus edit counts.
14
+
3
15
  ## 1.4.2
4
16
 
5
17
  ### Added
@@ -229,10 +229,8 @@ export interface LocalWorkdirEditPlan {
229
229
  }
230
230
  export interface LocalWorkdirEditResult {
231
231
  applied: LocalFileLinesPatch[];
232
- backups: Array<{
233
- path: string;
234
- content: string;
235
- }>;
232
+ changed_files: string[];
233
+ edit_count: number;
236
234
  }
237
235
  export type LocalPathSensitivity = "normal" | "sensitive" | "secret";
238
236
  export interface LocalPathSensitivityInfo {
@@ -647,7 +647,11 @@ export class LocalWorkdir {
647
647
  }
648
648
  throw error;
649
649
  }
650
- return { applied, backups };
650
+ return {
651
+ applied,
652
+ changed_files: uniqueStrings(applied.map((patch) => patch.path)),
653
+ edit_count: applied.length,
654
+ };
651
655
  }
652
656
  classifyPath(relativePath) {
653
657
  return classifyLocalPathSensitivity(relativePath);
@@ -1092,6 +1096,9 @@ function selectLineRange(lines, startLine, endLine) {
1092
1096
  }
1093
1097
  return { lines: lines.slice(startLine - 1, end), endLine: end };
1094
1098
  }
1099
+ function uniqueStrings(values) {
1100
+ return Array.from(new Set(values));
1101
+ }
1095
1102
  function patchLineRange(content, startLine, endLine, replacement) {
1096
1103
  const lines = splitLines(content);
1097
1104
  const selected = selectLineRange(lines, startLine, endLine);
@@ -1,4 +1,5 @@
1
1
  export * from "./core.js";
2
2
  export * from "./context.js";
3
+ export * from "./pause.js";
3
4
  export * from "./shell.js";
4
5
  export * from "./tools.js";
@@ -1,4 +1,5 @@
1
1
  export * from "./core.js";
2
2
  export * from "./context.js";
3
+ export * from "./pause.js";
3
4
  export * from "./shell.js";
4
5
  export * from "./tools.js";
@@ -0,0 +1,42 @@
1
+ import type { FunctionTool } from "../types/tools.js";
2
+ export interface LocalPauseRequest {
3
+ durationMs: number;
4
+ reason?: string;
5
+ }
6
+ export interface LocalPauseResult extends Record<string, unknown> {
7
+ ok: true;
8
+ tool: string;
9
+ action: "pause";
10
+ requested_ms: number;
11
+ elapsed_ms: number;
12
+ status: "completed" | "cancelled";
13
+ reason?: string;
14
+ resume_message?: string;
15
+ }
16
+ export interface LocalPauseHandle {
17
+ readonly request: LocalPauseRequest;
18
+ resume(message?: string): void;
19
+ }
20
+ export interface LocalPauseToolRegistryOptions {
21
+ maxDurationMs?: number;
22
+ toolName?: string;
23
+ onPauseStart?: (handle: LocalPauseHandle) => void;
24
+ onPauseEnd?: (result: LocalPauseResult) => void;
25
+ }
26
+ export interface LocalPauseToolRegistry {
27
+ readonly maxDurationMs: number;
28
+ readonly toolName: string;
29
+ definitions(): FunctionTool[];
30
+ handlers(): Record<string, (args: Record<string, unknown>) => Promise<Record<string, unknown>>>;
31
+ execute(name: string, args: Record<string, unknown>, context?: {
32
+ signal?: AbortSignal;
33
+ }): Promise<Record<string, unknown>>;
34
+ requiresApproval(name: string, args?: Record<string, unknown>): boolean;
35
+ }
36
+ export declare function createLocalPauseToolRegistry(options?: LocalPauseToolRegistryOptions): LocalPauseToolRegistry;
37
+ export declare function localPauseToolDefinition(name?: string, options?: {
38
+ maxDurationMs?: number;
39
+ }): FunctionTool;
40
+ export declare function localPauseToolInstructions(options?: {
41
+ maxDurationMs?: number;
42
+ }): string;
@@ -0,0 +1,122 @@
1
+ const defaultMaxDurationMs = 5 * 60 * 1000;
2
+ export function createLocalPauseToolRegistry(options = {}) {
3
+ const toolName = options.toolName ?? "local_pause";
4
+ const maxDurationMs = Math.max(1, Math.floor(options.maxDurationMs ?? defaultMaxDurationMs));
5
+ const definition = localPauseToolDefinition(toolName, { maxDurationMs });
6
+ return {
7
+ maxDurationMs,
8
+ toolName,
9
+ definitions: () => [{ ...definition }],
10
+ handlers: () => ({ [toolName]: (args) => executeLocalPause(toolName, args, { maxDurationMs, ...options }) }),
11
+ execute: async (name, args, context = {}) => {
12
+ if (name !== toolName) {
13
+ throw new Error(`unknown local pause tool: ${name}`);
14
+ }
15
+ return await executeLocalPause(toolName, args, { maxDurationMs, signal: context.signal, ...options });
16
+ },
17
+ requiresApproval: (name) => name === toolName && false,
18
+ };
19
+ }
20
+ export function localPauseToolDefinition(name = "local_pause", options = {}) {
21
+ return {
22
+ type: "function",
23
+ name,
24
+ description: localPauseToolInstructions(options),
25
+ parameters: localPauseToolParameters(options),
26
+ strict: false,
27
+ };
28
+ }
29
+ export function localPauseToolInstructions(options = {}) {
30
+ const maxDurationMs = Math.max(1, Math.floor(options.maxDurationMs ?? defaultMaxDurationMs));
31
+ return [
32
+ "Pause the local agentic workflow for a bounded amount of time, then continue automatically.",
33
+ "Use this only when waiting for external state such as CI, deployment rollout, rate-limit cooldown, file sync, or another asynchronous process.",
34
+ "The pause is local runtime control, not reasoning time. Keep the reason concrete.",
35
+ `Maximum duration: ${maxDurationMs} ms. The user may resume the pause early; early resume returns status=cancelled with elapsed_ms.`,
36
+ ].join(" ");
37
+ }
38
+ function localPauseToolParameters(options = {}) {
39
+ const maxDurationMs = Math.max(1, Math.floor(options.maxDurationMs ?? defaultMaxDurationMs));
40
+ return {
41
+ type: "object",
42
+ properties: {
43
+ duration_ms: {
44
+ type: "integer",
45
+ minimum: 1,
46
+ maximum: maxDurationMs,
47
+ description: "How long to wait before continuing automatically, in milliseconds.",
48
+ },
49
+ reason: {
50
+ type: "string",
51
+ description: "Short reason for the wait, such as the external state being awaited.",
52
+ },
53
+ },
54
+ required: ["duration_ms"],
55
+ additionalProperties: false,
56
+ };
57
+ }
58
+ async function executeLocalPause(toolName, args, options) {
59
+ const request = pauseRequest(args, options.maxDurationMs);
60
+ const startedAt = Date.now();
61
+ let settled = false;
62
+ let timer = null;
63
+ let abortHandler = null;
64
+ return await new Promise((resolve, reject) => {
65
+ const finish = (status, resumeMessage) => {
66
+ if (settled)
67
+ return;
68
+ settled = true;
69
+ if (timer)
70
+ clearTimeout(timer);
71
+ if (abortHandler)
72
+ options.signal?.removeEventListener("abort", abortHandler);
73
+ const result = {
74
+ ok: true,
75
+ tool: toolName,
76
+ action: "pause",
77
+ requested_ms: request.durationMs,
78
+ elapsed_ms: Math.max(0, Date.now() - startedAt),
79
+ status,
80
+ ...(request.reason ? { reason: request.reason } : {}),
81
+ ...(resumeMessage ? { resume_message: resumeMessage } : {}),
82
+ };
83
+ options.onPauseEnd?.(result);
84
+ resolve(result);
85
+ };
86
+ abortHandler = () => {
87
+ if (settled)
88
+ return;
89
+ settled = true;
90
+ if (timer)
91
+ clearTimeout(timer);
92
+ reject(new Error("local_pause aborted"));
93
+ };
94
+ if (options.signal?.aborted) {
95
+ abortHandler();
96
+ return;
97
+ }
98
+ options.signal?.addEventListener("abort", abortHandler);
99
+ options.onPauseStart?.({
100
+ request,
101
+ resume(message) {
102
+ finish("cancelled", message);
103
+ },
104
+ });
105
+ timer = setTimeout(() => finish("completed"), request.durationMs);
106
+ });
107
+ }
108
+ function pauseRequest(args, maxDurationMs) {
109
+ const raw = args.duration_ms ?? args.durationMs;
110
+ if (typeof raw !== "number" || !Number.isFinite(raw)) {
111
+ throw new Error("local_pause duration_ms must be a finite number");
112
+ }
113
+ const durationMs = Math.floor(raw);
114
+ if (durationMs < 1) {
115
+ throw new Error("local_pause duration_ms must be at least 1");
116
+ }
117
+ if (durationMs > maxDurationMs) {
118
+ throw new Error(`local_pause duration_ms must be <= ${maxDurationMs}`);
119
+ }
120
+ const reason = typeof args.reason === "string" && args.reason.trim() ? args.reason.trim() : undefined;
121
+ return { durationMs, reason };
122
+ }
package/dist/version.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export declare const VERSION = "1.4.2";
2
- export declare const USER_AGENT = "@agent-api/sdk/1.4.2";
1
+ export declare const VERSION = "1.4.4";
2
+ export declare const USER_AGENT = "@agent-api/sdk/1.4.4";
package/dist/version.js CHANGED
@@ -1,2 +1,2 @@
1
- export const VERSION = "1.4.2";
1
+ export const VERSION = "1.4.4";
2
2
  export const USER_AGENT = `@agent-api/sdk/${VERSION}`;
@@ -665,7 +665,11 @@ class LocalWorkdir {
665
665
  }
666
666
  throw error;
667
667
  }
668
- return { applied, backups };
668
+ return {
669
+ applied,
670
+ changed_files: uniqueStrings(applied.map((patch) => patch.path)),
671
+ edit_count: applied.length,
672
+ };
669
673
  }
670
674
  classifyPath(relativePath) {
671
675
  return classifyLocalPathSensitivity(relativePath);
@@ -1112,6 +1116,9 @@ function selectLineRange(lines, startLine, endLine) {
1112
1116
  }
1113
1117
  return { lines: lines.slice(startLine - 1, end), endLine: end };
1114
1118
  }
1119
+ function uniqueStrings(values) {
1120
+ return Array.from(new Set(values));
1121
+ }
1115
1122
  function patchLineRange(content, startLine, endLine, replacement) {
1116
1123
  const lines = splitLines(content);
1117
1124
  const selected = selectLineRange(lines, startLine, endLine);
@@ -16,5 +16,6 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./core.js"), exports);
18
18
  __exportStar(require("./context.js"), exports);
19
+ __exportStar(require("./pause.js"), exports);
19
20
  __exportStar(require("./shell.js"), exports);
20
21
  __exportStar(require("./tools.js"), exports);
@@ -0,0 +1,127 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createLocalPauseToolRegistry = createLocalPauseToolRegistry;
4
+ exports.localPauseToolDefinition = localPauseToolDefinition;
5
+ exports.localPauseToolInstructions = localPauseToolInstructions;
6
+ const defaultMaxDurationMs = 5 * 60 * 1000;
7
+ function createLocalPauseToolRegistry(options = {}) {
8
+ const toolName = options.toolName ?? "local_pause";
9
+ const maxDurationMs = Math.max(1, Math.floor(options.maxDurationMs ?? defaultMaxDurationMs));
10
+ const definition = localPauseToolDefinition(toolName, { maxDurationMs });
11
+ return {
12
+ maxDurationMs,
13
+ toolName,
14
+ definitions: () => [{ ...definition }],
15
+ handlers: () => ({ [toolName]: (args) => executeLocalPause(toolName, args, { maxDurationMs, ...options }) }),
16
+ execute: async (name, args, context = {}) => {
17
+ if (name !== toolName) {
18
+ throw new Error(`unknown local pause tool: ${name}`);
19
+ }
20
+ return await executeLocalPause(toolName, args, { maxDurationMs, signal: context.signal, ...options });
21
+ },
22
+ requiresApproval: (name) => name === toolName && false,
23
+ };
24
+ }
25
+ function localPauseToolDefinition(name = "local_pause", options = {}) {
26
+ return {
27
+ type: "function",
28
+ name,
29
+ description: localPauseToolInstructions(options),
30
+ parameters: localPauseToolParameters(options),
31
+ strict: false,
32
+ };
33
+ }
34
+ function localPauseToolInstructions(options = {}) {
35
+ const maxDurationMs = Math.max(1, Math.floor(options.maxDurationMs ?? defaultMaxDurationMs));
36
+ return [
37
+ "Pause the local agentic workflow for a bounded amount of time, then continue automatically.",
38
+ "Use this only when waiting for external state such as CI, deployment rollout, rate-limit cooldown, file sync, or another asynchronous process.",
39
+ "The pause is local runtime control, not reasoning time. Keep the reason concrete.",
40
+ `Maximum duration: ${maxDurationMs} ms. The user may resume the pause early; early resume returns status=cancelled with elapsed_ms.`,
41
+ ].join(" ");
42
+ }
43
+ function localPauseToolParameters(options = {}) {
44
+ const maxDurationMs = Math.max(1, Math.floor(options.maxDurationMs ?? defaultMaxDurationMs));
45
+ return {
46
+ type: "object",
47
+ properties: {
48
+ duration_ms: {
49
+ type: "integer",
50
+ minimum: 1,
51
+ maximum: maxDurationMs,
52
+ description: "How long to wait before continuing automatically, in milliseconds.",
53
+ },
54
+ reason: {
55
+ type: "string",
56
+ description: "Short reason for the wait, such as the external state being awaited.",
57
+ },
58
+ },
59
+ required: ["duration_ms"],
60
+ additionalProperties: false,
61
+ };
62
+ }
63
+ async function executeLocalPause(toolName, args, options) {
64
+ const request = pauseRequest(args, options.maxDurationMs);
65
+ const startedAt = Date.now();
66
+ let settled = false;
67
+ let timer = null;
68
+ let abortHandler = null;
69
+ return await new Promise((resolve, reject) => {
70
+ const finish = (status, resumeMessage) => {
71
+ if (settled)
72
+ return;
73
+ settled = true;
74
+ if (timer)
75
+ clearTimeout(timer);
76
+ if (abortHandler)
77
+ options.signal?.removeEventListener("abort", abortHandler);
78
+ const result = {
79
+ ok: true,
80
+ tool: toolName,
81
+ action: "pause",
82
+ requested_ms: request.durationMs,
83
+ elapsed_ms: Math.max(0, Date.now() - startedAt),
84
+ status,
85
+ ...(request.reason ? { reason: request.reason } : {}),
86
+ ...(resumeMessage ? { resume_message: resumeMessage } : {}),
87
+ };
88
+ options.onPauseEnd?.(result);
89
+ resolve(result);
90
+ };
91
+ abortHandler = () => {
92
+ if (settled)
93
+ return;
94
+ settled = true;
95
+ if (timer)
96
+ clearTimeout(timer);
97
+ reject(new Error("local_pause aborted"));
98
+ };
99
+ if (options.signal?.aborted) {
100
+ abortHandler();
101
+ return;
102
+ }
103
+ options.signal?.addEventListener("abort", abortHandler);
104
+ options.onPauseStart?.({
105
+ request,
106
+ resume(message) {
107
+ finish("cancelled", message);
108
+ },
109
+ });
110
+ timer = setTimeout(() => finish("completed"), request.durationMs);
111
+ });
112
+ }
113
+ function pauseRequest(args, maxDurationMs) {
114
+ const raw = args.duration_ms ?? args.durationMs;
115
+ if (typeof raw !== "number" || !Number.isFinite(raw)) {
116
+ throw new Error("local_pause duration_ms must be a finite number");
117
+ }
118
+ const durationMs = Math.floor(raw);
119
+ if (durationMs < 1) {
120
+ throw new Error("local_pause duration_ms must be at least 1");
121
+ }
122
+ if (durationMs > maxDurationMs) {
123
+ throw new Error(`local_pause duration_ms must be <= ${maxDurationMs}`);
124
+ }
125
+ const reason = typeof args.reason === "string" && args.reason.trim() ? args.reason.trim() : undefined;
126
+ return { durationMs, reason };
127
+ }
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.USER_AGENT = exports.VERSION = void 0;
4
- exports.VERSION = "1.4.2";
4
+ exports.VERSION = "1.4.4";
5
5
  exports.USER_AGENT = `@agent-api/sdk/${exports.VERSION}`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-api/sdk",
3
- "version": "1.4.2",
3
+ "version": "1.4.4",
4
4
  "description": "Production JavaScript SDK for the Managed Agent API",
5
5
  "license": "MIT",
6
6
  "repository": {