@agent-api/sdk 1.1.1 → 1.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.
- package/CHANGELOG.md +11 -0
- package/README.md +26 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.js +2 -0
- package/dist/local/index.d.ts +1 -0
- package/dist/local/index.js +1 -0
- package/dist/local/tools.d.ts +34 -0
- package/dist/local/tools.js +373 -0
- package/dist/preset-tools.d.ts +53 -0
- package/dist/preset-tools.js +85 -0
- package/dist/resources/responses.js +2 -0
- package/dist/tool-validation.d.ts +2 -0
- package/dist/tool-validation.js +15 -0
- package/dist/version.d.ts +2 -2
- package/dist/version.js +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# Changelog — @agent-api/sdk
|
|
2
2
|
|
|
3
|
+
## 1.1.2
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- Added a model-facing `local_workspace` driver/tool primitive for local workspace operations.
|
|
8
|
+
- Added approval-aware dispatch for mutating local workspace actions.
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
|
|
12
|
+
- Replaced fragmented local workspace tool presentation with an action-based adapter over the low-level local APIs.
|
|
13
|
+
|
|
3
14
|
## 1.1.1
|
|
4
15
|
|
|
5
16
|
### Added
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Production JavaScript/TypeScript SDK for the Managed Agent API.
|
|
4
4
|
|
|
5
|
-
**Published on npm:** [`@agent-api/sdk`](https://www.npmjs.com/package/@agent-api/sdk) (v1.1.
|
|
5
|
+
**Published on npm:** [`@agent-api/sdk`](https://www.npmjs.com/package/@agent-api/sdk) (v1.1.3)
|
|
6
6
|
|
|
7
7
|
## Install
|
|
8
8
|
|
|
@@ -97,6 +97,31 @@ const response = await client.agent.create({
|
|
|
97
97
|
});
|
|
98
98
|
```
|
|
99
99
|
|
|
100
|
+
## Preset tools and local/client tools
|
|
101
|
+
|
|
102
|
+
`tools` is the concrete model-visible tool list. Tool names must be unique because model tool calls select tools by name. When you send `preset` and `tools` together, the explicit `tools` array replaces the preset's default tools. Hybrid apps that add local function tools should resolve the preset defaults first, merge in their local tools, then pass the merged array. The SDK rejects duplicate tool names before submitting requests.
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
import { resolvePresetTools } from "@agent-api/sdk";
|
|
106
|
+
import { createLocalWorkspaceToolRegistry, LocalWorkspace } from "@agent-api/sdk/local";
|
|
107
|
+
|
|
108
|
+
const workspace = new LocalWorkspace("/path/to/project", { trusted: true });
|
|
109
|
+
const registry = createLocalWorkspaceToolRegistry(workspace);
|
|
110
|
+
|
|
111
|
+
const { tools } = await resolvePresetTools(client, {
|
|
112
|
+
preset: "pro-search",
|
|
113
|
+
tools: registry.definitions(),
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
const response = await client.agent.create({
|
|
117
|
+
preset: "pro-search",
|
|
118
|
+
input: "Research the topic and update local notes.",
|
|
119
|
+
tools,
|
|
120
|
+
});
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
For long-running apps, cache `client.presets.list()` and `client.tools.list()` and refresh them periodically. Use `resolvePresetToolsFromCatalog()` with cached catalogs when you want deterministic request construction without fetching on every turn.
|
|
124
|
+
|
|
100
125
|
## Skills
|
|
101
126
|
|
|
102
127
|
`localSkillFromDirectory()` reads `SKILL.md` into the descriptor for initial local-skill auto-focus; later focused reads still use the local skill tool bridge.
|
package/dist/index.d.ts
CHANGED
|
@@ -5,6 +5,10 @@ export { APIError, APIConnectionError, APIStatusError, AuthenticationError, BadR
|
|
|
5
5
|
export * from "./types/index.js";
|
|
6
6
|
export { functionCallOutputInput, pendingFunctionCalls, runLocalFunctionHandlers, } from "./local-functions.js";
|
|
7
7
|
export type { LocalFunctionHandler, LocalFunctionHandlers } from "./local-functions.js";
|
|
8
|
+
export { mergeTools, publicToolToRequestTool, resolvePresetTools, resolvePresetToolsFromCatalog, } from "./preset-tools.js";
|
|
9
|
+
export type { PresetToolCatalogClient, ResolvePresetToolsOptions, ResolvePresetToolsResult, UnknownPresetToolBehavior, } from "./preset-tools.js";
|
|
10
|
+
export { LocalWorkspaceDriver, createLocalWorkspaceToolRegistry, localWorkspaceToolDefinition, localWorkspaceToolInstructions, } from "./local/tools.js";
|
|
11
|
+
export type { LocalWorkspaceAction, LocalWorkspaceAccessMode, LocalWorkspaceToolRegistry, LocalWorkspaceToolRegistryOptions, } from "./local/tools.js";
|
|
8
12
|
export { localSkillFromDirectory, pendingLocalSkillCalls, runLocalSkillHandlers } from "./local-skills.js";
|
|
9
13
|
export type { LocalSkillDirectoryOptions } from "./local-skills.js";
|
|
10
14
|
export { AuthResource, DeviceAuthFlowError } from "./resources/auth.js";
|
package/dist/index.js
CHANGED
|
@@ -3,5 +3,7 @@ export { Page, collectPage } from "./pagination.js";
|
|
|
3
3
|
export { APIError, APIConnectionError, APIStatusError, AuthenticationError, BadRequestError, InternalServerError, NotFoundError, PermissionDeniedError, RateLimitError, isRetryableStatus, parseResponseError, } from "./errors.js";
|
|
4
4
|
export * from "./types/index.js";
|
|
5
5
|
export { functionCallOutputInput, pendingFunctionCalls, runLocalFunctionHandlers, } from "./local-functions.js";
|
|
6
|
+
export { mergeTools, publicToolToRequestTool, resolvePresetTools, resolvePresetToolsFromCatalog, } from "./preset-tools.js";
|
|
7
|
+
export { LocalWorkspaceDriver, createLocalWorkspaceToolRegistry, localWorkspaceToolDefinition, localWorkspaceToolInstructions, } from "./local/tools.js";
|
|
6
8
|
export { localSkillFromDirectory, pendingLocalSkillCalls, runLocalSkillHandlers } from "./local-skills.js";
|
|
7
9
|
export { AuthResource, DeviceAuthFlowError } from "./resources/auth.js";
|
package/dist/local/index.d.ts
CHANGED
package/dist/local/index.js
CHANGED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { FunctionTool } from "../types/tools.js";
|
|
2
|
+
import type { LocalWorkspace } from "./core.js";
|
|
3
|
+
export type LocalWorkspaceAccessMode = "approval" | "full";
|
|
4
|
+
export type LocalWorkspaceAction = "summarize" | "list" | "search" | "grep" | "read" | "read_lines" | "context" | "snapshot" | "classify_path" | "preview_edits" | "apply_edits" | "write" | "mkdir" | "delete";
|
|
5
|
+
export interface LocalWorkspaceToolRegistryOptions {
|
|
6
|
+
accessMode?: LocalWorkspaceAccessMode;
|
|
7
|
+
toolName?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface LocalWorkspaceToolRegistry {
|
|
10
|
+
readonly workspace: LocalWorkspace;
|
|
11
|
+
readonly accessMode: LocalWorkspaceAccessMode;
|
|
12
|
+
readonly toolName: string;
|
|
13
|
+
definitions(): FunctionTool[];
|
|
14
|
+
handlers(): Record<string, (args: Record<string, unknown>) => Promise<Record<string, unknown>>>;
|
|
15
|
+
execute(name: string, args: Record<string, unknown>): Promise<Record<string, unknown>>;
|
|
16
|
+
requiresApproval(name: string, args?: Record<string, unknown>): boolean;
|
|
17
|
+
}
|
|
18
|
+
export interface LocalWorkspaceDriverOptions {
|
|
19
|
+
accessMode?: LocalWorkspaceAccessMode;
|
|
20
|
+
}
|
|
21
|
+
export declare class LocalWorkspaceDriver {
|
|
22
|
+
readonly workspace: LocalWorkspace;
|
|
23
|
+
readonly accessMode: LocalWorkspaceAccessMode;
|
|
24
|
+
constructor(workspace: LocalWorkspace, options?: LocalWorkspaceDriverOptions);
|
|
25
|
+
dispatch(args: Record<string, unknown>): Promise<Record<string, unknown>>;
|
|
26
|
+
requiresApproval(args: Record<string, unknown>): boolean;
|
|
27
|
+
private dispatchApplyEdits;
|
|
28
|
+
private dispatchWrite;
|
|
29
|
+
private dispatchMkdir;
|
|
30
|
+
private dispatchDelete;
|
|
31
|
+
}
|
|
32
|
+
export declare function createLocalWorkspaceToolRegistry(workspace: LocalWorkspace, options?: LocalWorkspaceToolRegistryOptions): LocalWorkspaceToolRegistry;
|
|
33
|
+
export declare function localWorkspaceToolDefinition(name?: string): FunctionTool;
|
|
34
|
+
export declare function localWorkspaceToolInstructions(): string;
|
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
import { createLocalContextPackage } from "./context.js";
|
|
2
|
+
export class LocalWorkspaceDriver {
|
|
3
|
+
workspace;
|
|
4
|
+
accessMode;
|
|
5
|
+
constructor(workspace, options = {}) {
|
|
6
|
+
this.workspace = workspace;
|
|
7
|
+
this.accessMode = options.accessMode ?? "approval";
|
|
8
|
+
}
|
|
9
|
+
async dispatch(args) {
|
|
10
|
+
const action = workspaceAction(args);
|
|
11
|
+
switch (action) {
|
|
12
|
+
case "summarize":
|
|
13
|
+
return localToolResult(action, localSummaryResult(await this.workspace.summarize(summaryArgs(args))));
|
|
14
|
+
case "list":
|
|
15
|
+
return localToolResult(action, await this.workspace.listEntries(optionalStringArg(args, "path") ?? ".", listArgs(args)));
|
|
16
|
+
case "search":
|
|
17
|
+
return localToolResult(action, await this.workspace.searchEntries(searchEntriesArgs(args)));
|
|
18
|
+
case "grep":
|
|
19
|
+
return localToolResult(action, await this.workspace.grep(grepArgs(args)));
|
|
20
|
+
case "read":
|
|
21
|
+
return localToolResult(action, await this.workspace.readFile(stringArg(args, "path"), readFileArgs(args)));
|
|
22
|
+
case "read_lines":
|
|
23
|
+
return localToolResult(action, await this.workspace.readLines(stringArg(args, "path"), readLinesArgs(args)));
|
|
24
|
+
case "context":
|
|
25
|
+
return localToolResult(action, await createLocalContextPackage(this.workspace, contextPackageArgs(args)));
|
|
26
|
+
case "snapshot":
|
|
27
|
+
return localToolResult(action, await this.workspace.snapshot(snapshotArgs(args)));
|
|
28
|
+
case "classify_path":
|
|
29
|
+
return localToolResult(action, this.workspace.classifyPath(stringArg(args, "path")));
|
|
30
|
+
case "preview_edits":
|
|
31
|
+
return localToolResult(action, await this.workspace.previewEdits(editsArg(args)));
|
|
32
|
+
case "apply_edits":
|
|
33
|
+
return await this.dispatchApplyEdits(args);
|
|
34
|
+
case "write":
|
|
35
|
+
return await this.dispatchWrite(args);
|
|
36
|
+
case "mkdir":
|
|
37
|
+
return await this.dispatchMkdir(args);
|
|
38
|
+
case "delete":
|
|
39
|
+
return await this.dispatchDelete(args);
|
|
40
|
+
default:
|
|
41
|
+
throw new Error(`unsupported local_workspace action: ${action}`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
requiresApproval(args) {
|
|
45
|
+
if (this.accessMode === "full") {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
return mutatingLocalWorkspaceActions.has(workspaceAction(args));
|
|
49
|
+
}
|
|
50
|
+
async dispatchApplyEdits(args) {
|
|
51
|
+
const edits = editsArg(args);
|
|
52
|
+
if (this.accessMode !== "full") {
|
|
53
|
+
return approvalRequired("apply_edits", args, await this.workspace.previewEdits(edits));
|
|
54
|
+
}
|
|
55
|
+
return localToolResult("apply_edits", await this.workspace.applyEdits(edits));
|
|
56
|
+
}
|
|
57
|
+
async dispatchWrite(args) {
|
|
58
|
+
if (this.accessMode !== "full") {
|
|
59
|
+
return approvalRequired("write", args);
|
|
60
|
+
}
|
|
61
|
+
return localToolResult("write", await this.workspace.writeText(stringArg(args, "path"), stringArg(args, "content")));
|
|
62
|
+
}
|
|
63
|
+
async dispatchMkdir(args) {
|
|
64
|
+
if (this.accessMode !== "full") {
|
|
65
|
+
return approvalRequired("mkdir", args);
|
|
66
|
+
}
|
|
67
|
+
return localToolResult("mkdir", await this.workspace.createDirectory(stringArg(args, "path")));
|
|
68
|
+
}
|
|
69
|
+
async dispatchDelete(args) {
|
|
70
|
+
if (this.accessMode !== "full") {
|
|
71
|
+
return approvalRequired("delete", args);
|
|
72
|
+
}
|
|
73
|
+
return localToolResult("delete", await this.workspace.deletePath(stringArg(args, "path")));
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
export function createLocalWorkspaceToolRegistry(workspace, options = {}) {
|
|
77
|
+
const toolName = options.toolName ?? "local_workspace";
|
|
78
|
+
const driver = new LocalWorkspaceDriver(workspace, { accessMode: options.accessMode });
|
|
79
|
+
const definition = localWorkspaceToolDefinition(toolName);
|
|
80
|
+
return {
|
|
81
|
+
workspace,
|
|
82
|
+
accessMode: driver.accessMode,
|
|
83
|
+
toolName,
|
|
84
|
+
definitions: () => [{ ...definition }],
|
|
85
|
+
handlers: () => ({ [toolName]: (args) => driver.dispatch(args) }),
|
|
86
|
+
execute: async (name, args) => {
|
|
87
|
+
if (name !== toolName) {
|
|
88
|
+
throw new Error(`unknown local workspace tool: ${name}`);
|
|
89
|
+
}
|
|
90
|
+
return await driver.dispatch(args);
|
|
91
|
+
},
|
|
92
|
+
requiresApproval: (name, args = {}) => name === toolName && driver.requiresApproval(args),
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
export function localWorkspaceToolDefinition(name = "local_workspace") {
|
|
96
|
+
return {
|
|
97
|
+
type: "function",
|
|
98
|
+
name,
|
|
99
|
+
description: localWorkspaceToolDescription,
|
|
100
|
+
parameters: localWorkspaceToolParameters(),
|
|
101
|
+
strict: false,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
export function localWorkspaceToolInstructions() {
|
|
105
|
+
return localWorkspaceToolDescription;
|
|
106
|
+
}
|
|
107
|
+
const localWorkspaceActions = [
|
|
108
|
+
"summarize",
|
|
109
|
+
"list",
|
|
110
|
+
"search",
|
|
111
|
+
"grep",
|
|
112
|
+
"read",
|
|
113
|
+
"read_lines",
|
|
114
|
+
"context",
|
|
115
|
+
"snapshot",
|
|
116
|
+
"classify_path",
|
|
117
|
+
"preview_edits",
|
|
118
|
+
"apply_edits",
|
|
119
|
+
"write",
|
|
120
|
+
"mkdir",
|
|
121
|
+
"delete",
|
|
122
|
+
];
|
|
123
|
+
const mutatingLocalWorkspaceActions = new Set([
|
|
124
|
+
"apply_edits",
|
|
125
|
+
"write",
|
|
126
|
+
"mkdir",
|
|
127
|
+
"delete",
|
|
128
|
+
]);
|
|
129
|
+
const localWorkspaceToolDescription = [
|
|
130
|
+
"Inspect and modify the selected local workspace through one model-facing primitive.",
|
|
131
|
+
"Use action=list/search/grep/summarize/context to discover files, read/read_lines for file content, preview_edits before edits, and apply_edits/write/mkdir/delete only when mutation is intended.",
|
|
132
|
+
"In approval mode, mutating actions return requires_approval with a safe preview instead of changing files. In full mode, mutating actions execute immediately.",
|
|
133
|
+
"Paths are relative to the selected local workspace; never use absolute paths.",
|
|
134
|
+
].join(" ");
|
|
135
|
+
function localWorkspaceToolParameters() {
|
|
136
|
+
return objectSchema({
|
|
137
|
+
action: {
|
|
138
|
+
type: "string",
|
|
139
|
+
enum: localWorkspaceActions,
|
|
140
|
+
description: "Workspace operation. Prefer summarize/list/search/grep before reading or editing. Prefer read_lines and apply_edits for source changes.",
|
|
141
|
+
},
|
|
142
|
+
path: stringSchema("Relative path. File path for read/write/delete/edit actions; directory base for list/search/grep/summarize/context/snapshot."),
|
|
143
|
+
query: stringSchema("Path/name query for search, or optional context query."),
|
|
144
|
+
pattern: stringSchema("Literal text pattern for grep."),
|
|
145
|
+
content: stringSchema("Text content for write."),
|
|
146
|
+
start_line: integerSchema("1-based start line for read_lines and edit entries."),
|
|
147
|
+
end_line: integerSchema("1-based inclusive end line; omit or 0 for EOF when supported."),
|
|
148
|
+
replacement: stringSchema("Replacement text for simple single edit flows."),
|
|
149
|
+
edits: {
|
|
150
|
+
type: "array",
|
|
151
|
+
minItems: 1,
|
|
152
|
+
description: "Line edits for preview_edits/apply_edits.",
|
|
153
|
+
items: objectSchema({
|
|
154
|
+
path: requiredStringSchema("Relative file path."),
|
|
155
|
+
start_line: requiredIntegerSchema("1-based start line."),
|
|
156
|
+
end_line: integerSchema("1-based inclusive end line."),
|
|
157
|
+
replacement: stringSchema("Replacement text. Empty string deletes the line range."),
|
|
158
|
+
expected_sha256: stringSchema("Optional expected SHA-256 for conflict detection."),
|
|
159
|
+
}, ["path", "start_line"]),
|
|
160
|
+
},
|
|
161
|
+
options: objectSchema({
|
|
162
|
+
recursive: booleanSchema("List recursively."),
|
|
163
|
+
include_directories: booleanSchema("Include directories in list results."),
|
|
164
|
+
max_depth: integerSchema("Maximum recursive list depth."),
|
|
165
|
+
limit: integerSchema("Maximum entries or matches."),
|
|
166
|
+
max_files: integerSchema("Maximum files to scan or package."),
|
|
167
|
+
max_bytes: integerSchema("Maximum total bytes to read/package."),
|
|
168
|
+
max_bytes_per_file: integerSchema("Maximum bytes per file."),
|
|
169
|
+
max_previews: integerSchema("Maximum summary previews."),
|
|
170
|
+
include_content: booleanSchema("Include file contents in context packages."),
|
|
171
|
+
include_summary: booleanSchema("Include workspace summary in context packages."),
|
|
172
|
+
include_search: booleanSchema("Include grep results in context packages when query is set."),
|
|
173
|
+
include_secrets: booleanSchema("Include likely secret file contents in context packages."),
|
|
174
|
+
hash: booleanSchema("Include SHA-256 hashes in snapshots."),
|
|
175
|
+
}),
|
|
176
|
+
}, ["action"]);
|
|
177
|
+
}
|
|
178
|
+
function workspaceAction(args) {
|
|
179
|
+
const value = stringArg(args, "action").trim().toLowerCase();
|
|
180
|
+
if (!localWorkspaceActions.includes(value)) {
|
|
181
|
+
throw new Error(`unsupported local_workspace action: ${value}`);
|
|
182
|
+
}
|
|
183
|
+
return value;
|
|
184
|
+
}
|
|
185
|
+
function summaryArgs(args) {
|
|
186
|
+
return {
|
|
187
|
+
path: optionalStringArg(args, "path"),
|
|
188
|
+
maxFiles: optionalNumberArg(args, "maxFiles", "max_files"),
|
|
189
|
+
maxPreviews: optionalNumberArg(args, "maxPreviews", "max_previews"),
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
function grepArgs(args) {
|
|
193
|
+
return {
|
|
194
|
+
pattern: stringArg(args, "pattern"),
|
|
195
|
+
path: optionalStringArg(args, "path"),
|
|
196
|
+
limit: optionalNumberArg(args, "limit"),
|
|
197
|
+
maxFiles: optionalNumberArg(args, "maxFiles", "max_files"),
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
function listArgs(args) {
|
|
201
|
+
return {
|
|
202
|
+
recursive: optionalBooleanArg(args, "recursive"),
|
|
203
|
+
includeDirectories: optionalBooleanArg(args, "includeDirectories", "include_directories"),
|
|
204
|
+
maxDepth: optionalNumberArg(args, "maxDepth", "max_depth"),
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
function searchEntriesArgs(args) {
|
|
208
|
+
return {
|
|
209
|
+
query: stringArg(args, "query"),
|
|
210
|
+
path: optionalStringArg(args, "path"),
|
|
211
|
+
limit: optionalNumberArg(args, "limit"),
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
function readFileArgs(args) {
|
|
215
|
+
return {
|
|
216
|
+
maxBytes: optionalNumberArg(args, "maxBytes", "max_bytes"),
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
function readLinesArgs(args) {
|
|
220
|
+
return {
|
|
221
|
+
startLine: numberArg(args, "startLine", "start_line"),
|
|
222
|
+
endLine: optionalNumberArg(args, "endLine", "end_line"),
|
|
223
|
+
maxBytes: optionalNumberArg(args, "maxBytes", "max_bytes"),
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
function snapshotArgs(args) {
|
|
227
|
+
return {
|
|
228
|
+
path: optionalStringArg(args, "path"),
|
|
229
|
+
hash: optionalBooleanArg(args, "hash"),
|
|
230
|
+
maxBytesPerFile: optionalNumberArg(args, "maxBytesPerFile", "max_bytes_per_file"),
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
function contextPackageArgs(args) {
|
|
234
|
+
return {
|
|
235
|
+
path: optionalStringArg(args, "path"),
|
|
236
|
+
query: optionalStringArg(args, "query"),
|
|
237
|
+
maxFiles: optionalNumberArg(args, "maxFiles", "max_files"),
|
|
238
|
+
maxBytes: optionalNumberArg(args, "maxBytes", "max_bytes"),
|
|
239
|
+
maxBytesPerFile: optionalNumberArg(args, "maxBytesPerFile", "max_bytes_per_file"),
|
|
240
|
+
includeContent: optionalBooleanArg(args, "includeContent", "include_content"),
|
|
241
|
+
includeSummary: optionalBooleanArg(args, "includeSummary", "include_summary"),
|
|
242
|
+
includeSearch: optionalBooleanArg(args, "includeSearch", "include_search"),
|
|
243
|
+
includeSecrets: optionalBooleanArg(args, "includeSecrets", "include_secrets"),
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
function editsArg(args) {
|
|
247
|
+
const edits = args.edits;
|
|
248
|
+
if (Array.isArray(edits) && edits.length > 0) {
|
|
249
|
+
return edits.map((edit) => {
|
|
250
|
+
if (!edit || typeof edit !== "object") {
|
|
251
|
+
throw new Error("each edit must be an object");
|
|
252
|
+
}
|
|
253
|
+
return editArg(edit);
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
if (typeof args.path === "string" && typeof (args.startLine ?? args.start_line) === "number") {
|
|
257
|
+
return [editArg(args)];
|
|
258
|
+
}
|
|
259
|
+
throw new Error("edits must be a non-empty array");
|
|
260
|
+
}
|
|
261
|
+
function editArg(record) {
|
|
262
|
+
return {
|
|
263
|
+
path: stringArg(record, "path"),
|
|
264
|
+
startLine: numberArg(record, "startLine", "start_line"),
|
|
265
|
+
endLine: optionalNumberArg(record, "endLine", "end_line"),
|
|
266
|
+
replacement: typeof record.replacement === "string" ? record.replacement : "",
|
|
267
|
+
expectedSha256: optionalStringArg(record, "expectedSha256", "expected_sha256"),
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
function localSummaryResult(summary) {
|
|
271
|
+
return summary;
|
|
272
|
+
}
|
|
273
|
+
function localToolResult(action, value) {
|
|
274
|
+
const result = value;
|
|
275
|
+
if (result && typeof result === "object" && !Array.isArray(result)) {
|
|
276
|
+
return { ok: true, action, ...result };
|
|
277
|
+
}
|
|
278
|
+
return { ok: true, action, result };
|
|
279
|
+
}
|
|
280
|
+
function stringArg(args, key, alternateKey) {
|
|
281
|
+
const direct = args[key] ?? (alternateKey ? args[alternateKey] : undefined);
|
|
282
|
+
const fromOptions = args.options && typeof args.options === "object"
|
|
283
|
+
? args.options[key] ?? (alternateKey ? args.options[alternateKey] : undefined)
|
|
284
|
+
: undefined;
|
|
285
|
+
const value = direct ?? fromOptions;
|
|
286
|
+
if (typeof value !== "string" || !value.trim()) {
|
|
287
|
+
throw new Error(`${key} must be a non-empty string`);
|
|
288
|
+
}
|
|
289
|
+
return value;
|
|
290
|
+
}
|
|
291
|
+
function optionalStringArg(args, key, alternateKey) {
|
|
292
|
+
const direct = args[key] ?? (alternateKey ? args[alternateKey] : undefined);
|
|
293
|
+
const fromOptions = args.options && typeof args.options === "object"
|
|
294
|
+
? args.options[key] ?? (alternateKey ? args.options[alternateKey] : undefined)
|
|
295
|
+
: undefined;
|
|
296
|
+
const value = direct ?? fromOptions;
|
|
297
|
+
if (value == null || value === "")
|
|
298
|
+
return undefined;
|
|
299
|
+
if (typeof value !== "string") {
|
|
300
|
+
throw new Error(`${key} must be a string`);
|
|
301
|
+
}
|
|
302
|
+
return value;
|
|
303
|
+
}
|
|
304
|
+
function numberArg(args, key, alternateKey) {
|
|
305
|
+
const direct = args[key] ?? (alternateKey ? args[alternateKey] : undefined);
|
|
306
|
+
const fromOptions = args.options && typeof args.options === "object"
|
|
307
|
+
? args.options[key] ?? (alternateKey ? args.options[alternateKey] : undefined)
|
|
308
|
+
: undefined;
|
|
309
|
+
const value = direct ?? fromOptions;
|
|
310
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
311
|
+
throw new Error(`${key} must be a number`);
|
|
312
|
+
}
|
|
313
|
+
return Math.trunc(value);
|
|
314
|
+
}
|
|
315
|
+
function optionalNumberArg(args, key, alternateKey) {
|
|
316
|
+
const direct = args[key] ?? (alternateKey ? args[alternateKey] : undefined);
|
|
317
|
+
const fromOptions = args.options && typeof args.options === "object"
|
|
318
|
+
? args.options[key] ?? (alternateKey ? args.options[alternateKey] : undefined)
|
|
319
|
+
: undefined;
|
|
320
|
+
const value = direct ?? fromOptions;
|
|
321
|
+
if (value == null)
|
|
322
|
+
return undefined;
|
|
323
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
324
|
+
throw new Error(`${key} must be a number`);
|
|
325
|
+
}
|
|
326
|
+
return Math.trunc(value);
|
|
327
|
+
}
|
|
328
|
+
function optionalBooleanArg(args, key, alternateKey) {
|
|
329
|
+
const direct = args[key] ?? (alternateKey ? args[alternateKey] : undefined);
|
|
330
|
+
const fromOptions = args.options && typeof args.options === "object"
|
|
331
|
+
? args.options[key] ?? (alternateKey ? args.options[alternateKey] : undefined)
|
|
332
|
+
: undefined;
|
|
333
|
+
const value = direct ?? fromOptions;
|
|
334
|
+
if (value == null)
|
|
335
|
+
return undefined;
|
|
336
|
+
if (typeof value !== "boolean") {
|
|
337
|
+
throw new Error(`${key} must be a boolean`);
|
|
338
|
+
}
|
|
339
|
+
return value;
|
|
340
|
+
}
|
|
341
|
+
function approvalRequired(action, args, preview) {
|
|
342
|
+
return {
|
|
343
|
+
ok: false,
|
|
344
|
+
action,
|
|
345
|
+
requires_approval: true,
|
|
346
|
+
arguments: args,
|
|
347
|
+
preview,
|
|
348
|
+
message: `local_workspace action ${action} requires approval`,
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
function objectSchema(properties, required = []) {
|
|
352
|
+
return {
|
|
353
|
+
type: "object",
|
|
354
|
+
properties,
|
|
355
|
+
required,
|
|
356
|
+
additionalProperties: false,
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
function stringSchema(description) {
|
|
360
|
+
return { type: "string", description };
|
|
361
|
+
}
|
|
362
|
+
function requiredStringSchema(description) {
|
|
363
|
+
return stringSchema(description);
|
|
364
|
+
}
|
|
365
|
+
function integerSchema(description) {
|
|
366
|
+
return { type: "integer", description };
|
|
367
|
+
}
|
|
368
|
+
function booleanSchema(description) {
|
|
369
|
+
return { type: "boolean", description };
|
|
370
|
+
}
|
|
371
|
+
function requiredIntegerSchema(description) {
|
|
372
|
+
return integerSchema(description);
|
|
373
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { ListPresetsResponse, Preset } from "./types/catalog.js";
|
|
2
|
+
import type { ListToolsResponse, PublicTool, Tool } from "./types/tools.js";
|
|
3
|
+
export interface PresetToolCatalogClient {
|
|
4
|
+
presets: {
|
|
5
|
+
list(): Promise<ListPresetsResponse>;
|
|
6
|
+
};
|
|
7
|
+
tools: {
|
|
8
|
+
list(): Promise<ListToolsResponse>;
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
export type UnknownPresetToolBehavior = "stub" | "omit" | "error";
|
|
12
|
+
export interface ResolvePresetToolsOptions {
|
|
13
|
+
/**
|
|
14
|
+
* Preset id whose policy.allowed_tools should be resolved.
|
|
15
|
+
*/
|
|
16
|
+
preset: string;
|
|
17
|
+
/**
|
|
18
|
+
* Additional caller/client tools to append after the preset tools.
|
|
19
|
+
*/
|
|
20
|
+
tools?: readonly Tool[];
|
|
21
|
+
/**
|
|
22
|
+
* Optional pre-fetched preset catalog. Use this when your app caches discovery
|
|
23
|
+
* responses and wants deterministic request construction.
|
|
24
|
+
*/
|
|
25
|
+
presets?: readonly Preset[];
|
|
26
|
+
/**
|
|
27
|
+
* Optional pre-fetched tool catalog.
|
|
28
|
+
*/
|
|
29
|
+
toolCatalog?: readonly PublicTool[];
|
|
30
|
+
/**
|
|
31
|
+
* Behavior when a preset allows a tool that is not present in the supplied
|
|
32
|
+
* or fetched tool catalog. "stub" keeps a name-only tool definition so the
|
|
33
|
+
* backend can still enrich it by name.
|
|
34
|
+
*/
|
|
35
|
+
unknownPresetTool?: UnknownPresetToolBehavior;
|
|
36
|
+
}
|
|
37
|
+
export interface ResolvePresetToolsResult {
|
|
38
|
+
preset: Preset;
|
|
39
|
+
tools: Tool[];
|
|
40
|
+
missingToolNames: string[];
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Resolve a preset's allowed tool names into concrete request tools and append
|
|
44
|
+
* caller-provided tools. This is a convenience for hybrid apps that need to add
|
|
45
|
+
* local/client tools while preserving the preset's default server tools.
|
|
46
|
+
*
|
|
47
|
+
* The Agent API request surface remains OpenAI-compatible: the returned array
|
|
48
|
+
* is intended for the normal CreateResponseRequest.tools field.
|
|
49
|
+
*/
|
|
50
|
+
export declare function resolvePresetTools(client: PresetToolCatalogClient, options: ResolvePresetToolsOptions): Promise<ResolvePresetToolsResult>;
|
|
51
|
+
export declare function resolvePresetToolsFromCatalog(options: ResolvePresetToolsOptions): ResolvePresetToolsResult;
|
|
52
|
+
export declare function mergeTools(...groups: Array<readonly Tool[]>): Tool[];
|
|
53
|
+
export declare function publicToolToRequestTool(tool: PublicTool): Tool;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { validateUniqueToolNames } from "./tool-validation.js";
|
|
2
|
+
/**
|
|
3
|
+
* Resolve a preset's allowed tool names into concrete request tools and append
|
|
4
|
+
* caller-provided tools. This is a convenience for hybrid apps that need to add
|
|
5
|
+
* local/client tools while preserving the preset's default server tools.
|
|
6
|
+
*
|
|
7
|
+
* The Agent API request surface remains OpenAI-compatible: the returned array
|
|
8
|
+
* is intended for the normal CreateResponseRequest.tools field.
|
|
9
|
+
*/
|
|
10
|
+
export async function resolvePresetTools(client, options) {
|
|
11
|
+
const presets = options.presets ?? (await client.presets.list()).data;
|
|
12
|
+
const toolCatalog = options.toolCatalog ?? (await client.tools.list()).data;
|
|
13
|
+
return resolvePresetToolsFromCatalog({ ...options, presets, toolCatalog });
|
|
14
|
+
}
|
|
15
|
+
export function resolvePresetToolsFromCatalog(options) {
|
|
16
|
+
const presetId = options.preset.trim();
|
|
17
|
+
if (!presetId) {
|
|
18
|
+
throw new Error("preset is required");
|
|
19
|
+
}
|
|
20
|
+
const preset = options.presets?.find((row) => row.preset === presetId);
|
|
21
|
+
if (!preset) {
|
|
22
|
+
throw new Error(`preset not found: ${presetId}`);
|
|
23
|
+
}
|
|
24
|
+
const catalogByName = new Map();
|
|
25
|
+
for (const tool of options.toolCatalog ?? []) {
|
|
26
|
+
const name = tool.name?.trim();
|
|
27
|
+
if (name)
|
|
28
|
+
catalogByName.set(name, tool);
|
|
29
|
+
}
|
|
30
|
+
const missingToolNames = [];
|
|
31
|
+
const presetTools = [];
|
|
32
|
+
const unknownPresetTool = options.unknownPresetTool ?? "stub";
|
|
33
|
+
for (const name of preset.policy?.allowed_tools ?? []) {
|
|
34
|
+
const trimmed = name.trim();
|
|
35
|
+
if (!trimmed)
|
|
36
|
+
continue;
|
|
37
|
+
const catalogTool = catalogByName.get(trimmed);
|
|
38
|
+
if (catalogTool) {
|
|
39
|
+
presetTools.push(publicToolToRequestTool(catalogTool));
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
missingToolNames.push(trimmed);
|
|
43
|
+
if (unknownPresetTool === "error") {
|
|
44
|
+
throw new Error(`preset tool not found in catalog: ${trimmed}`);
|
|
45
|
+
}
|
|
46
|
+
if (unknownPresetTool === "stub") {
|
|
47
|
+
presetTools.push({ name: trimmed });
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
preset,
|
|
52
|
+
tools: mergeTools(presetTools, options.tools ?? []),
|
|
53
|
+
missingToolNames,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
export function mergeTools(...groups) {
|
|
57
|
+
const out = [];
|
|
58
|
+
for (const group of groups) {
|
|
59
|
+
for (const tool of group) {
|
|
60
|
+
const name = tool.name?.trim();
|
|
61
|
+
if (!name) {
|
|
62
|
+
throw new Error("tools[].name is required");
|
|
63
|
+
}
|
|
64
|
+
out.push({ ...tool, name });
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
validateUniqueToolNames(out);
|
|
68
|
+
return out;
|
|
69
|
+
}
|
|
70
|
+
export function publicToolToRequestTool(tool) {
|
|
71
|
+
const out = { name: tool.name };
|
|
72
|
+
if (tool.type)
|
|
73
|
+
out.type = tool.type;
|
|
74
|
+
if (tool.description)
|
|
75
|
+
out.description = tool.description;
|
|
76
|
+
if (tool.parameters)
|
|
77
|
+
out.parameters = tool.parameters;
|
|
78
|
+
if (tool.max_tokens != null)
|
|
79
|
+
out.max_tokens = tool.max_tokens;
|
|
80
|
+
if (tool.max_tokens_per_page != null)
|
|
81
|
+
out.max_tokens_per_page = tool.max_tokens_per_page;
|
|
82
|
+
if (tool.version)
|
|
83
|
+
out.version = tool.version;
|
|
84
|
+
return out;
|
|
85
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { addOutputText } from "../internal/output-text.js";
|
|
2
2
|
import { buildQuery } from "../internal/query.js";
|
|
3
3
|
import { collectPage } from "../pagination.js";
|
|
4
|
+
import { validateUniqueToolNames } from "../tool-validation.js";
|
|
4
5
|
export class ResponsesResource {
|
|
5
6
|
http;
|
|
6
7
|
path;
|
|
@@ -9,6 +10,7 @@ export class ResponsesResource {
|
|
|
9
10
|
this.path = path;
|
|
10
11
|
}
|
|
11
12
|
create(params, options) {
|
|
13
|
+
validateUniqueToolNames(params.tools);
|
|
12
14
|
if (params.stream) {
|
|
13
15
|
return this.http.stream(this.path, params, options);
|
|
14
16
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export function validateUniqueToolNames(tools) {
|
|
2
|
+
if (!tools)
|
|
3
|
+
return;
|
|
4
|
+
const seen = new Set();
|
|
5
|
+
for (const tool of tools) {
|
|
6
|
+
const name = tool.name?.trim();
|
|
7
|
+
if (!name) {
|
|
8
|
+
throw new Error("tools[].name is required");
|
|
9
|
+
}
|
|
10
|
+
if (seen.has(name)) {
|
|
11
|
+
throw new Error(`duplicate tools[].name: ${name}`);
|
|
12
|
+
}
|
|
13
|
+
seen.add(name);
|
|
14
|
+
}
|
|
15
|
+
}
|
package/dist/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const VERSION = "1.1.
|
|
2
|
-
export declare const USER_AGENT = "@agent-api/sdk/1.1.
|
|
1
|
+
export declare const VERSION = "1.1.3";
|
|
2
|
+
export declare const USER_AGENT = "@agent-api/sdk/1.1.3";
|
package/dist/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const VERSION = "1.1.
|
|
1
|
+
export const VERSION = "1.1.3";
|
|
2
2
|
export const USER_AGENT = `@agent-api/sdk/${VERSION}`;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-api/sdk",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.3",
|
|
4
4
|
"description": "Production JavaScript SDK for the Managed Agent API",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"build": "tsc -p tsconfig.json",
|
|
47
47
|
"sync-version": "node scripts/sync-version.mjs",
|
|
48
48
|
"prepack": "npm run sync-version && npm run build",
|
|
49
|
-
"test": "npm run sync-version && npm run build && node --test test/index.test.mjs test/local-function-integration.test.mjs test/local-runtime.test.mjs",
|
|
49
|
+
"test": "npm run sync-version && npm run build && node --test test/index.test.mjs test/local-function-integration.test.mjs test/local-runtime.test.mjs test/local-tools.test.mjs",
|
|
50
50
|
"test:integration": "npm run sync-version && npm run build && node --test test/integration.test.mjs",
|
|
51
51
|
"test:integration:local-functions": "npm run sync-version && npm run build && node --test test/local-function-integration.test.mjs",
|
|
52
52
|
"check:routes": "node scripts/check-routes.mjs"
|