@nextclaw/ncp-agent-runtime 0.3.8 → 0.3.10
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/dist/index.d.ts +45 -2
- package/dist/index.js +229 -178
- package/package.json +2 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { NcpAgentConversationStateManager, NcpAgentRunInput, NcpAgentRunOptions, NcpAgentRuntime, NcpAssistantReasoningNormalizationMode, NcpContextBuilder, NcpContextPrepareOptions, NcpEncodeContext, NcpEndpointEvent, NcpLLMApi, NcpLLMApiInput, NcpLLMApiOptions, NcpMessagePart, NcpRoundBuffer, NcpStreamEncoder, NcpTool, NcpToolCallResult, NcpToolDefinition, NcpToolRegistry, OpenAIChatChunk, OpenAIContentPart } from "@nextclaw/ncp";
|
|
1
|
+
import { NcpAgentConversationStateManager, NcpAgentRunInput, NcpAgentRunOptions, NcpAgentRuntime, NcpAssistantReasoningNormalizationMode, NcpContextBuilder, NcpContextPrepareOptions, NcpEncodeContext, NcpEndpointEvent, NcpInvalidToolArgumentsResult, NcpLLMApi, NcpLLMApiInput, NcpLLMApiOptions, NcpMessagePart, NcpRoundBuffer, NcpStreamEncoder, NcpTool, NcpToolCallResult, NcpToolDefinition, NcpToolRegistry, OpenAIChatChunk, OpenAIContentPart, OpenAITool } from "@nextclaw/ncp";
|
|
2
2
|
|
|
3
3
|
//#region src/asset-store.d.ts
|
|
4
4
|
type StoredAssetRecord = {
|
|
@@ -166,7 +166,50 @@ declare class DefaultNcpAgentRuntime implements NcpAgentRuntime {
|
|
|
166
166
|
* The stream encoder does not emit RunFinished; it only converts chunks to NCP events.
|
|
167
167
|
*/
|
|
168
168
|
private runLoop;
|
|
169
|
+
private executeToolCall;
|
|
170
|
+
private resolveValidationIssues;
|
|
171
|
+
private executeValidatedToolCall;
|
|
169
172
|
private tapStream;
|
|
170
173
|
}
|
|
171
174
|
//#endregion
|
|
172
|
-
|
|
175
|
+
//#region src/utils.d.ts
|
|
176
|
+
type ParsedToolArgs = {
|
|
177
|
+
ok: true;
|
|
178
|
+
rawText: string;
|
|
179
|
+
value: Record<string, unknown>;
|
|
180
|
+
} | {
|
|
181
|
+
ok: false;
|
|
182
|
+
rawText: string;
|
|
183
|
+
issues: string[];
|
|
184
|
+
};
|
|
185
|
+
declare function genId(): string;
|
|
186
|
+
declare function getOpenAiFunctionParametersSchemaIssues(schema: Record<string, unknown> | undefined): string[];
|
|
187
|
+
declare function assertOpenAiFunctionParametersSchema(params: {
|
|
188
|
+
toolName: string;
|
|
189
|
+
schema: Record<string, unknown> | undefined;
|
|
190
|
+
}): void;
|
|
191
|
+
declare function buildOpenAiFunctionTool(definition: NcpToolDefinition): OpenAITool;
|
|
192
|
+
declare function parseToolArgs(args: unknown): ParsedToolArgs;
|
|
193
|
+
declare function validateToolArgs(args: Record<string, unknown>, schema: Record<string, unknown> | undefined): string[];
|
|
194
|
+
declare function createInvalidToolArgumentsResult(params: {
|
|
195
|
+
toolCallId: string;
|
|
196
|
+
toolName: string;
|
|
197
|
+
rawArgumentsText: string;
|
|
198
|
+
issues: string[];
|
|
199
|
+
}): NcpInvalidToolArgumentsResult;
|
|
200
|
+
declare function createToolExecutionFailedResult(params: {
|
|
201
|
+
toolCallId: string;
|
|
202
|
+
toolName: string;
|
|
203
|
+
error: unknown;
|
|
204
|
+
}): {
|
|
205
|
+
ok: false;
|
|
206
|
+
error: {
|
|
207
|
+
code: "tool_execution_failed";
|
|
208
|
+
message: string;
|
|
209
|
+
toolCallId: string;
|
|
210
|
+
toolName: string;
|
|
211
|
+
};
|
|
212
|
+
};
|
|
213
|
+
declare function appendToolRoundToInput(input: NcpLLMApiInput, reasoning: string, text: string, toolResults: ReadonlyArray<NcpToolCallResult>): NcpLLMApiInput;
|
|
214
|
+
//#endregion
|
|
215
|
+
export { type AssetMeta, type AssetPutInput, type AssetRef, DefaultNcpAgentRuntime, type DefaultNcpAgentRuntimeConfig, DefaultNcpContextBuilder, DefaultNcpRoundBuffer, DefaultNcpStreamEncoder, DefaultNcpToolRegistry, EchoNcpLLMApi, LocalAssetStore, type StoredAssetRecord, appendToolRoundToInput, assertOpenAiFunctionParametersSchema, buildAssetContentPath, buildNcpUserContent, buildOpenAiFunctionTool, createInvalidToolArgumentsResult, createToolExecutionFailedResult, genId, getOpenAiFunctionParametersSchemaIssues, isTextLikeAsset, parseToolArgs, validateToolArgs };
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { copyFileSync, existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import AjvPkg from "ajv";
|
|
2
3
|
import { createHash, randomUUID } from "node:crypto";
|
|
3
4
|
import { copyFile, mkdir, readFile, stat, writeFile } from "node:fs/promises";
|
|
4
5
|
import { basename, dirname, join, resolve } from "node:path";
|
|
@@ -146,6 +147,177 @@ function buildNcpUserContent(parts, options = {}) {
|
|
|
146
147
|
return content;
|
|
147
148
|
}
|
|
148
149
|
//#endregion
|
|
150
|
+
//#region src/utils.ts
|
|
151
|
+
const toolSchemaValidator = new AjvPkg({
|
|
152
|
+
allErrors: true,
|
|
153
|
+
strict: false,
|
|
154
|
+
removeAdditional: false
|
|
155
|
+
});
|
|
156
|
+
const validatorCache = /* @__PURE__ */ new WeakMap();
|
|
157
|
+
const DISALLOWED_OPENAI_TOOL_SCHEMA_TOP_LEVEL_KEYWORDS = [
|
|
158
|
+
"oneOf",
|
|
159
|
+
"anyOf",
|
|
160
|
+
"allOf",
|
|
161
|
+
"enum",
|
|
162
|
+
"not"
|
|
163
|
+
];
|
|
164
|
+
function genId() {
|
|
165
|
+
return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 11)}`;
|
|
166
|
+
}
|
|
167
|
+
function isRecord$1(value) {
|
|
168
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
169
|
+
}
|
|
170
|
+
function stringifyRawArgs(args) {
|
|
171
|
+
if (typeof args === "string") return args;
|
|
172
|
+
if (args && typeof args === "object" && !Array.isArray(args)) try {
|
|
173
|
+
return JSON.stringify(args);
|
|
174
|
+
} catch {
|
|
175
|
+
return "[unserializable-object]";
|
|
176
|
+
}
|
|
177
|
+
return String(args ?? "");
|
|
178
|
+
}
|
|
179
|
+
function getOpenAiFunctionParametersSchemaIssues(schema) {
|
|
180
|
+
if (!schema) return ["parameters must be declared as a JSON Schema object"];
|
|
181
|
+
if (!isRecord$1(schema)) return ["parameters must be a JSON Schema object"];
|
|
182
|
+
const issues = [];
|
|
183
|
+
if (schema.type !== "object") issues.push("root schema must set type to \"object\"");
|
|
184
|
+
for (const keyword of DISALLOWED_OPENAI_TOOL_SCHEMA_TOP_LEVEL_KEYWORDS) if (keyword in schema) issues.push(`root schema must not declare top-level "${keyword}"`);
|
|
185
|
+
return issues;
|
|
186
|
+
}
|
|
187
|
+
function assertOpenAiFunctionParametersSchema(params) {
|
|
188
|
+
const issues = getOpenAiFunctionParametersSchemaIssues(params.schema);
|
|
189
|
+
if (issues.length === 0) return;
|
|
190
|
+
throw new Error(`Tool "${params.toolName}" declares an unsupported OpenAI-compatible parameters schema: ${issues.join("; ")}. See docs/internal/openai-tool-schema.md.`);
|
|
191
|
+
}
|
|
192
|
+
function buildOpenAiFunctionTool(definition) {
|
|
193
|
+
assertOpenAiFunctionParametersSchema({
|
|
194
|
+
toolName: definition.name,
|
|
195
|
+
schema: definition.parameters
|
|
196
|
+
});
|
|
197
|
+
return {
|
|
198
|
+
type: "function",
|
|
199
|
+
function: {
|
|
200
|
+
name: definition.name,
|
|
201
|
+
description: definition.description,
|
|
202
|
+
parameters: definition.parameters
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
function parseToolArgs(args) {
|
|
207
|
+
if (args && typeof args === "object" && !Array.isArray(args)) return {
|
|
208
|
+
ok: true,
|
|
209
|
+
rawText: stringifyRawArgs(args),
|
|
210
|
+
value: args
|
|
211
|
+
};
|
|
212
|
+
const rawText = stringifyRawArgs(args);
|
|
213
|
+
if (typeof args !== "string") return {
|
|
214
|
+
ok: false,
|
|
215
|
+
rawText,
|
|
216
|
+
issues: ["Tool arguments must be a JSON object string."]
|
|
217
|
+
};
|
|
218
|
+
const trimmed = args.trim();
|
|
219
|
+
if (!trimmed) return {
|
|
220
|
+
ok: false,
|
|
221
|
+
rawText,
|
|
222
|
+
issues: ["Tool arguments are empty."]
|
|
223
|
+
};
|
|
224
|
+
try {
|
|
225
|
+
const parsed = JSON.parse(trimmed);
|
|
226
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return {
|
|
227
|
+
ok: false,
|
|
228
|
+
rawText,
|
|
229
|
+
issues: ["Tool arguments JSON must decode to an object."]
|
|
230
|
+
};
|
|
231
|
+
return {
|
|
232
|
+
ok: true,
|
|
233
|
+
rawText,
|
|
234
|
+
value: parsed
|
|
235
|
+
};
|
|
236
|
+
} catch (error) {
|
|
237
|
+
return {
|
|
238
|
+
ok: false,
|
|
239
|
+
rawText,
|
|
240
|
+
issues: [error instanceof Error ? error.message : "Failed to parse tool arguments JSON."]
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
function validateToolArgs(args, schema) {
|
|
245
|
+
if (!schema) return [];
|
|
246
|
+
const validate = getOrCreateValidator(schema);
|
|
247
|
+
if (validate(args)) return [];
|
|
248
|
+
return formatSchemaIssues(validate.errors);
|
|
249
|
+
}
|
|
250
|
+
function getOrCreateValidator(schema) {
|
|
251
|
+
const cached = validatorCache.get(schema);
|
|
252
|
+
if (cached) return cached;
|
|
253
|
+
const validate = toolSchemaValidator.compile(schema);
|
|
254
|
+
validatorCache.set(schema, validate);
|
|
255
|
+
return validate;
|
|
256
|
+
}
|
|
257
|
+
function formatSchemaIssues(errors) {
|
|
258
|
+
if (!errors || errors.length === 0) return ["Tool arguments do not match the declared schema."];
|
|
259
|
+
return errors.map((error) => {
|
|
260
|
+
const instancePath = error.instancePath.replace(/^\//, "").replace(/\//g, ".");
|
|
261
|
+
if (error.keyword === "required" && "missingProperty" in error.params && typeof error.params.missingProperty === "string") return `${instancePath ? `${instancePath}.${error.params.missingProperty}` : error.params.missingProperty} is required`;
|
|
262
|
+
if (error.keyword === "additionalProperties" && "additionalProperty" in error.params && typeof error.params.additionalProperty === "string") return `${instancePath ? `${instancePath}.${error.params.additionalProperty}` : error.params.additionalProperty} is not allowed`;
|
|
263
|
+
return `${instancePath || "parameter"}: ${error.message ?? "invalid"}`;
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
function createInvalidToolArgumentsResult(params) {
|
|
267
|
+
const { toolCallId, toolName, rawArgumentsText, issues } = params;
|
|
268
|
+
return {
|
|
269
|
+
ok: false,
|
|
270
|
+
error: {
|
|
271
|
+
code: "invalid_tool_arguments",
|
|
272
|
+
message: "Tool arguments are invalid.",
|
|
273
|
+
toolCallId,
|
|
274
|
+
toolName,
|
|
275
|
+
rawArgumentsText,
|
|
276
|
+
issues
|
|
277
|
+
}
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
function createToolExecutionFailedResult(params) {
|
|
281
|
+
const { toolCallId, toolName, error } = params;
|
|
282
|
+
return {
|
|
283
|
+
ok: false,
|
|
284
|
+
error: {
|
|
285
|
+
code: "tool_execution_failed",
|
|
286
|
+
message: error instanceof Error ? error.message : String(error),
|
|
287
|
+
toolCallId,
|
|
288
|
+
toolName
|
|
289
|
+
}
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
function appendToolRoundToInput(input, reasoning, text, toolResults) {
|
|
293
|
+
const assistantMsg = {
|
|
294
|
+
role: "assistant",
|
|
295
|
+
content: text || null,
|
|
296
|
+
...reasoning ? { reasoning_content: reasoning } : {},
|
|
297
|
+
tool_calls: toolResults.map((tr) => ({
|
|
298
|
+
id: tr.toolCallId,
|
|
299
|
+
type: "function",
|
|
300
|
+
function: {
|
|
301
|
+
name: tr.toolName,
|
|
302
|
+
arguments: tr.rawArgsText
|
|
303
|
+
}
|
|
304
|
+
}))
|
|
305
|
+
};
|
|
306
|
+
const toolMsgs = toolResults.map((tr) => ({
|
|
307
|
+
role: "tool",
|
|
308
|
+
content: typeof tr.result === "string" ? tr.result : JSON.stringify(tr.result ?? {}),
|
|
309
|
+
tool_call_id: tr.toolCallId
|
|
310
|
+
}));
|
|
311
|
+
return {
|
|
312
|
+
...input,
|
|
313
|
+
messages: [
|
|
314
|
+
...input.messages,
|
|
315
|
+
assistantMsg,
|
|
316
|
+
...toolMsgs
|
|
317
|
+
]
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
//#endregion
|
|
149
321
|
//#region src/context-builder.ts
|
|
150
322
|
function isRecord(value) {
|
|
151
323
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
@@ -261,14 +433,7 @@ var DefaultNcpContextBuilder = class {
|
|
|
261
433
|
for (const msg of sessionMessages.slice(-maxMessages)) messages.push(...messageToOpenAI(msg, { assetStore: this.assetStore }));
|
|
262
434
|
for (const msg of input.messages) messages.push(...messageToOpenAI(msg, { assetStore: this.assetStore }));
|
|
263
435
|
const toolDefinitions = this.toolRegistry?.getToolDefinitions() ?? [];
|
|
264
|
-
const tools = (requestedToolNames.length > 0 ? toolDefinitions.filter((definition) => requestedToolNames.includes(definition.name)) : toolDefinitions).map(
|
|
265
|
-
type: "function",
|
|
266
|
-
function: {
|
|
267
|
-
name: definition.name,
|
|
268
|
-
description: definition.description,
|
|
269
|
-
parameters: definition.parameters
|
|
270
|
-
}
|
|
271
|
-
}));
|
|
436
|
+
const tools = (requestedToolNames.length > 0 ? toolDefinitions.filter((definition) => requestedToolNames.includes(definition.name)) : toolDefinitions).map(buildOpenAiFunctionTool);
|
|
272
437
|
return {
|
|
273
438
|
messages,
|
|
274
439
|
tools: tools && tools.length > 0 ? tools : void 0,
|
|
@@ -858,143 +1023,6 @@ var EchoNcpLLMApi = class {
|
|
|
858
1023
|
};
|
|
859
1024
|
};
|
|
860
1025
|
//#endregion
|
|
861
|
-
//#region src/utils.ts
|
|
862
|
-
function genId() {
|
|
863
|
-
return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 11)}`;
|
|
864
|
-
}
|
|
865
|
-
function stringifyRawArgs(args) {
|
|
866
|
-
if (typeof args === "string") return args;
|
|
867
|
-
if (args && typeof args === "object" && !Array.isArray(args)) try {
|
|
868
|
-
return JSON.stringify(args);
|
|
869
|
-
} catch {
|
|
870
|
-
return "[unserializable-object]";
|
|
871
|
-
}
|
|
872
|
-
return String(args ?? "");
|
|
873
|
-
}
|
|
874
|
-
function parseToolArgs(args) {
|
|
875
|
-
if (args && typeof args === "object" && !Array.isArray(args)) return {
|
|
876
|
-
ok: true,
|
|
877
|
-
rawText: stringifyRawArgs(args),
|
|
878
|
-
value: args
|
|
879
|
-
};
|
|
880
|
-
const rawText = stringifyRawArgs(args);
|
|
881
|
-
if (typeof args !== "string") return {
|
|
882
|
-
ok: false,
|
|
883
|
-
rawText,
|
|
884
|
-
issues: ["Tool arguments must be a JSON object string."]
|
|
885
|
-
};
|
|
886
|
-
const trimmed = args.trim();
|
|
887
|
-
if (!trimmed) return {
|
|
888
|
-
ok: false,
|
|
889
|
-
rawText,
|
|
890
|
-
issues: ["Tool arguments are empty."]
|
|
891
|
-
};
|
|
892
|
-
try {
|
|
893
|
-
const parsed = JSON.parse(trimmed);
|
|
894
|
-
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return {
|
|
895
|
-
ok: false,
|
|
896
|
-
rawText,
|
|
897
|
-
issues: ["Tool arguments JSON must decode to an object."]
|
|
898
|
-
};
|
|
899
|
-
return {
|
|
900
|
-
ok: true,
|
|
901
|
-
rawText,
|
|
902
|
-
value: parsed
|
|
903
|
-
};
|
|
904
|
-
} catch (error) {
|
|
905
|
-
return {
|
|
906
|
-
ok: false,
|
|
907
|
-
rawText,
|
|
908
|
-
issues: [error instanceof Error ? error.message : "Failed to parse tool arguments JSON."]
|
|
909
|
-
};
|
|
910
|
-
}
|
|
911
|
-
}
|
|
912
|
-
function validateToolArgs(args, schema) {
|
|
913
|
-
if (!schema) return [];
|
|
914
|
-
return validateToolValue(args, schema, "");
|
|
915
|
-
}
|
|
916
|
-
function validateToolValue(value, schema, path) {
|
|
917
|
-
const label = path || "parameter";
|
|
918
|
-
const type = typeof schema.type === "string" ? schema.type : void 0;
|
|
919
|
-
if (type && !matchesSchemaType(value, type)) return [`${label} should be ${type}`];
|
|
920
|
-
const errors = [];
|
|
921
|
-
if (schema.enum && !schema.enum.includes(value)) errors.push(`${label} must be one of ${JSON.stringify(schema.enum)}`);
|
|
922
|
-
if (typeof value === "number") {
|
|
923
|
-
if (schema.minimum !== void 0 && value < schema.minimum) errors.push(`${label} must be >= ${schema.minimum}`);
|
|
924
|
-
if (schema.maximum !== void 0 && value > schema.maximum) errors.push(`${label} must be <= ${schema.maximum}`);
|
|
925
|
-
}
|
|
926
|
-
if (typeof value === "string") {
|
|
927
|
-
if (schema.minLength !== void 0 && value.length < schema.minLength) errors.push(`${label} must be at least ${schema.minLength} chars`);
|
|
928
|
-
if (schema.maxLength !== void 0 && value.length > schema.maxLength) errors.push(`${label} must be at most ${schema.maxLength} chars`);
|
|
929
|
-
}
|
|
930
|
-
if (type === "object") {
|
|
931
|
-
const objectValue = value;
|
|
932
|
-
for (const key of schema.required ?? []) if (!(key in objectValue)) errors.push(`missing required ${path ? `${path}.${key}` : key}`);
|
|
933
|
-
const properties = schema.properties ?? {};
|
|
934
|
-
for (const [key, childValue] of Object.entries(objectValue)) {
|
|
935
|
-
const childSchema = properties[key];
|
|
936
|
-
if (!childSchema) continue;
|
|
937
|
-
errors.push(...validateToolValue(childValue, childSchema, path ? `${path}.${key}` : key));
|
|
938
|
-
}
|
|
939
|
-
}
|
|
940
|
-
if (type === "array" && schema.items && Array.isArray(value)) value.forEach((item, index) => {
|
|
941
|
-
errors.push(...validateToolValue(item, schema.items, `${label}[${index}]`));
|
|
942
|
-
});
|
|
943
|
-
return errors;
|
|
944
|
-
}
|
|
945
|
-
function matchesSchemaType(value, type) {
|
|
946
|
-
switch (type) {
|
|
947
|
-
case "string": return typeof value === "string";
|
|
948
|
-
case "integer": return typeof value === "number" && Number.isInteger(value);
|
|
949
|
-
case "number": return typeof value === "number";
|
|
950
|
-
case "boolean": return typeof value === "boolean";
|
|
951
|
-
case "array": return Array.isArray(value);
|
|
952
|
-
case "object": return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
953
|
-
default: return true;
|
|
954
|
-
}
|
|
955
|
-
}
|
|
956
|
-
function createInvalidToolArgumentsResult(params) {
|
|
957
|
-
return {
|
|
958
|
-
ok: false,
|
|
959
|
-
error: {
|
|
960
|
-
code: "invalid_tool_arguments",
|
|
961
|
-
message: "Tool arguments are invalid.",
|
|
962
|
-
toolCallId: params.toolCallId,
|
|
963
|
-
toolName: params.toolName,
|
|
964
|
-
rawArgumentsText: params.rawArgumentsText,
|
|
965
|
-
issues: params.issues
|
|
966
|
-
}
|
|
967
|
-
};
|
|
968
|
-
}
|
|
969
|
-
function appendToolRoundToInput(input, reasoning, text, toolResults) {
|
|
970
|
-
const assistantMsg = {
|
|
971
|
-
role: "assistant",
|
|
972
|
-
content: text || null,
|
|
973
|
-
...reasoning ? { reasoning_content: reasoning } : {},
|
|
974
|
-
tool_calls: toolResults.map((tr) => ({
|
|
975
|
-
id: tr.toolCallId,
|
|
976
|
-
type: "function",
|
|
977
|
-
function: {
|
|
978
|
-
name: tr.toolName,
|
|
979
|
-
arguments: tr.rawArgsText
|
|
980
|
-
}
|
|
981
|
-
}))
|
|
982
|
-
};
|
|
983
|
-
const toolMsgs = toolResults.map((tr) => ({
|
|
984
|
-
role: "tool",
|
|
985
|
-
content: typeof tr.result === "string" ? tr.result : JSON.stringify(tr.result ?? {}),
|
|
986
|
-
tool_call_id: tr.toolCallId
|
|
987
|
-
}));
|
|
988
|
-
return {
|
|
989
|
-
...input,
|
|
990
|
-
messages: [
|
|
991
|
-
...input.messages,
|
|
992
|
-
assistantMsg,
|
|
993
|
-
...toolMsgs
|
|
994
|
-
]
|
|
995
|
-
};
|
|
996
|
-
}
|
|
997
|
-
//#endregion
|
|
998
1026
|
//#region src/round-collector.ts
|
|
999
1027
|
var DefaultNcpRoundCollector = class {
|
|
1000
1028
|
rawText = "";
|
|
@@ -1115,43 +1143,14 @@ var DefaultNcpAgentRuntime = class {
|
|
|
1115
1143
|
for await (const event of this.streamEncoder.encode(tappedStream, ctx)) yield event;
|
|
1116
1144
|
const toolResults = [];
|
|
1117
1145
|
for (const toolCall of roundCollector.getToolCalls()) {
|
|
1118
|
-
const
|
|
1119
|
-
|
|
1120
|
-
let result;
|
|
1121
|
-
let args = null;
|
|
1122
|
-
if (!parsedArgs.ok) result = createInvalidToolArgumentsResult({
|
|
1123
|
-
toolCallId: toolCall.toolCallId,
|
|
1124
|
-
toolName: toolCall.toolName,
|
|
1125
|
-
rawArgumentsText: parsedArgs.rawText,
|
|
1126
|
-
issues: parsedArgs.issues
|
|
1127
|
-
});
|
|
1128
|
-
else {
|
|
1129
|
-
const schemaIssues = validateToolArgs(parsedArgs.value, tool?.parameters);
|
|
1130
|
-
const validationIssues = schemaIssues.length > 0 ? schemaIssues : typeof tool?.validateArgs === "function" ? tool.validateArgs(parsedArgs.value) : [];
|
|
1131
|
-
if (validationIssues.length > 0) result = createInvalidToolArgumentsResult({
|
|
1132
|
-
toolCallId: toolCall.toolCallId,
|
|
1133
|
-
toolName: toolCall.toolName,
|
|
1134
|
-
rawArgumentsText: parsedArgs.rawText,
|
|
1135
|
-
issues: validationIssues
|
|
1136
|
-
});
|
|
1137
|
-
else {
|
|
1138
|
-
args = parsedArgs.value;
|
|
1139
|
-
result = await this.toolRegistry.execute(toolCall.toolCallId, toolCall.toolName, parsedArgs.value);
|
|
1140
|
-
}
|
|
1141
|
-
}
|
|
1142
|
-
toolResults.push({
|
|
1143
|
-
toolCallId: toolCall.toolCallId,
|
|
1144
|
-
toolName: toolCall.toolName,
|
|
1145
|
-
args,
|
|
1146
|
-
rawArgsText: parsedArgs.rawText,
|
|
1147
|
-
result
|
|
1148
|
-
});
|
|
1146
|
+
const toolResult = await this.executeToolCall(toolCall);
|
|
1147
|
+
toolResults.push(toolResult);
|
|
1149
1148
|
yield {
|
|
1150
1149
|
type: NcpEventType.MessageToolCallResult,
|
|
1151
1150
|
payload: {
|
|
1152
1151
|
sessionId: ctx.sessionId,
|
|
1153
1152
|
toolCallId: toolCall.toolCallId,
|
|
1154
|
-
content: result
|
|
1153
|
+
content: toolResult.result
|
|
1155
1154
|
}
|
|
1156
1155
|
};
|
|
1157
1156
|
}
|
|
@@ -1170,6 +1169,58 @@ var DefaultNcpAgentRuntime = class {
|
|
|
1170
1169
|
currentInput = appendToolRoundToInput(currentInput, roundCollector.getReasoning(), roundCollector.getText(), toolResults);
|
|
1171
1170
|
}
|
|
1172
1171
|
};
|
|
1172
|
+
executeToolCall = async function(toolCall) {
|
|
1173
|
+
const tool = this.toolRegistry.getTool(toolCall.toolName);
|
|
1174
|
+
const parsedArgs = parseToolArgs(toolCall.args);
|
|
1175
|
+
if (!parsedArgs.ok) return {
|
|
1176
|
+
toolCallId: toolCall.toolCallId,
|
|
1177
|
+
toolName: toolCall.toolName,
|
|
1178
|
+
args: null,
|
|
1179
|
+
rawArgsText: parsedArgs.rawText,
|
|
1180
|
+
result: createInvalidToolArgumentsResult({
|
|
1181
|
+
toolCallId: toolCall.toolCallId,
|
|
1182
|
+
toolName: toolCall.toolName,
|
|
1183
|
+
rawArgumentsText: parsedArgs.rawText,
|
|
1184
|
+
issues: parsedArgs.issues
|
|
1185
|
+
})
|
|
1186
|
+
};
|
|
1187
|
+
const validationIssues = this.resolveValidationIssues(parsedArgs.value, tool);
|
|
1188
|
+
if (validationIssues.length > 0) return {
|
|
1189
|
+
toolCallId: toolCall.toolCallId,
|
|
1190
|
+
toolName: toolCall.toolName,
|
|
1191
|
+
args: null,
|
|
1192
|
+
rawArgsText: parsedArgs.rawText,
|
|
1193
|
+
result: createInvalidToolArgumentsResult({
|
|
1194
|
+
toolCallId: toolCall.toolCallId,
|
|
1195
|
+
toolName: toolCall.toolName,
|
|
1196
|
+
rawArgumentsText: parsedArgs.rawText,
|
|
1197
|
+
issues: validationIssues
|
|
1198
|
+
})
|
|
1199
|
+
};
|
|
1200
|
+
return {
|
|
1201
|
+
toolCallId: toolCall.toolCallId,
|
|
1202
|
+
toolName: toolCall.toolName,
|
|
1203
|
+
args: parsedArgs.value,
|
|
1204
|
+
rawArgsText: parsedArgs.rawText,
|
|
1205
|
+
result: await this.executeValidatedToolCall(toolCall, parsedArgs.value)
|
|
1206
|
+
};
|
|
1207
|
+
};
|
|
1208
|
+
resolveValidationIssues = function(args, tool) {
|
|
1209
|
+
const schemaIssues = validateToolArgs(args, tool?.parameters);
|
|
1210
|
+
if (schemaIssues.length > 0) return schemaIssues;
|
|
1211
|
+
return typeof tool?.validateArgs === "function" ? tool.validateArgs(args) : [];
|
|
1212
|
+
};
|
|
1213
|
+
executeValidatedToolCall = async function(toolCall, args) {
|
|
1214
|
+
try {
|
|
1215
|
+
return await this.toolRegistry.execute(toolCall.toolCallId, toolCall.toolName, args);
|
|
1216
|
+
} catch (error) {
|
|
1217
|
+
return createToolExecutionFailedResult({
|
|
1218
|
+
toolCallId: toolCall.toolCallId,
|
|
1219
|
+
toolName: toolCall.toolName,
|
|
1220
|
+
error
|
|
1221
|
+
});
|
|
1222
|
+
}
|
|
1223
|
+
};
|
|
1173
1224
|
tapStream = async function* (stream, onChunk) {
|
|
1174
1225
|
for await (const chunk of stream) {
|
|
1175
1226
|
onChunk(chunk);
|
|
@@ -1178,4 +1229,4 @@ var DefaultNcpAgentRuntime = class {
|
|
|
1178
1229
|
};
|
|
1179
1230
|
};
|
|
1180
1231
|
//#endregion
|
|
1181
|
-
export { DefaultNcpAgentRuntime, DefaultNcpContextBuilder, DefaultNcpRoundBuffer, DefaultNcpStreamEncoder, DefaultNcpToolRegistry, EchoNcpLLMApi, LocalAssetStore, buildAssetContentPath, buildNcpUserContent, isTextLikeAsset };
|
|
1232
|
+
export { DefaultNcpAgentRuntime, DefaultNcpContextBuilder, DefaultNcpRoundBuffer, DefaultNcpStreamEncoder, DefaultNcpToolRegistry, EchoNcpLLMApi, LocalAssetStore, appendToolRoundToInput, assertOpenAiFunctionParametersSchema, buildAssetContentPath, buildNcpUserContent, buildOpenAiFunctionTool, createInvalidToolArgumentsResult, createToolExecutionFailedResult, genId, getOpenAiFunctionParametersSchemaIssues, isTextLikeAsset, parseToolArgs, validateToolArgs };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nextclaw/ncp-agent-runtime",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.10",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Default agent runtime implementation built on NCP interfaces.",
|
|
6
6
|
"type": "module",
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
"dist"
|
|
16
16
|
],
|
|
17
17
|
"dependencies": {
|
|
18
|
+
"ajv": "^8.17.1",
|
|
18
19
|
"@nextclaw/ncp": "0.5.0"
|
|
19
20
|
},
|
|
20
21
|
"devDependencies": {
|