@nuvin/nuvin-core 1.5.2 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/VERSION +2 -2
- package/dist/index.d.ts +752 -11
- package/dist/index.js +853 -157
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -33,7 +33,8 @@ var AgentEventTypes = {
|
|
|
33
33
|
SubAgentStarted: "sub_agent_started",
|
|
34
34
|
SubAgentToolCall: "sub_agent_tool_call",
|
|
35
35
|
SubAgentToolResult: "sub_agent_tool_result",
|
|
36
|
-
SubAgentCompleted: "sub_agent_completed"
|
|
36
|
+
SubAgentCompleted: "sub_agent_completed",
|
|
37
|
+
SubAgentMetrics: "sub_agent_metrics"
|
|
37
38
|
};
|
|
38
39
|
|
|
39
40
|
// src/metrics.ts
|
|
@@ -375,6 +376,391 @@ var PersistingConsoleEventPort = class {
|
|
|
375
376
|
}
|
|
376
377
|
};
|
|
377
378
|
|
|
379
|
+
// src/tools/tool-call-parser.ts
|
|
380
|
+
function parseJSON(jsonString) {
|
|
381
|
+
try {
|
|
382
|
+
const parsed = JSON.parse(jsonString || "{}");
|
|
383
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
384
|
+
return {
|
|
385
|
+
success: false,
|
|
386
|
+
error: "Parsed JSON must be an object, not an array or primitive"
|
|
387
|
+
};
|
|
388
|
+
}
|
|
389
|
+
return { success: true, data: parsed };
|
|
390
|
+
} catch (error) {
|
|
391
|
+
return {
|
|
392
|
+
success: false,
|
|
393
|
+
error: error instanceof Error ? error.message : "Invalid JSON syntax"
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
// src/tools/tool-validators.ts
|
|
399
|
+
var validateBashToolParams = (params) => {
|
|
400
|
+
const errors = [];
|
|
401
|
+
if (!params.cmd || typeof params.cmd !== "string") {
|
|
402
|
+
errors.push('Required parameter "cmd" must be a non-empty string');
|
|
403
|
+
}
|
|
404
|
+
if (params.cwd !== void 0 && typeof params.cwd !== "string") {
|
|
405
|
+
errors.push('Parameter "cwd" must be a string');
|
|
406
|
+
}
|
|
407
|
+
if (params.timeoutMs !== void 0) {
|
|
408
|
+
if (typeof params.timeoutMs !== "number" || params.timeoutMs < 1) {
|
|
409
|
+
errors.push('Parameter "timeoutMs" must be a positive number');
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
if (params.description !== void 0 && typeof params.description !== "string") {
|
|
413
|
+
errors.push('Parameter "description" must be a string');
|
|
414
|
+
}
|
|
415
|
+
if (errors.length > 0) {
|
|
416
|
+
return { valid: false, errors };
|
|
417
|
+
}
|
|
418
|
+
return {
|
|
419
|
+
valid: true,
|
|
420
|
+
data: {
|
|
421
|
+
cmd: params.cmd,
|
|
422
|
+
cwd: params.cwd,
|
|
423
|
+
timeoutMs: params.timeoutMs,
|
|
424
|
+
description: params.description
|
|
425
|
+
}
|
|
426
|
+
};
|
|
427
|
+
};
|
|
428
|
+
var validateFileReadParams = (params) => {
|
|
429
|
+
const errors = [];
|
|
430
|
+
if (!params.path || typeof params.path !== "string") {
|
|
431
|
+
errors.push('Required parameter "path" must be a non-empty string');
|
|
432
|
+
}
|
|
433
|
+
if (params.lineStart !== void 0) {
|
|
434
|
+
if (typeof params.lineStart !== "number" || params.lineStart < 1) {
|
|
435
|
+
errors.push('Parameter "lineStart" must be a positive integer');
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
if (params.lineEnd !== void 0) {
|
|
439
|
+
if (typeof params.lineEnd !== "number" || params.lineEnd < 1) {
|
|
440
|
+
errors.push('Parameter "lineEnd" must be a positive integer');
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
if (params.description !== void 0 && typeof params.description !== "string") {
|
|
444
|
+
errors.push('Parameter "description" must be a string');
|
|
445
|
+
}
|
|
446
|
+
if (errors.length > 0) {
|
|
447
|
+
return { valid: false, errors };
|
|
448
|
+
}
|
|
449
|
+
return {
|
|
450
|
+
valid: true,
|
|
451
|
+
data: {
|
|
452
|
+
path: params.path,
|
|
453
|
+
lineStart: params.lineStart,
|
|
454
|
+
lineEnd: params.lineEnd,
|
|
455
|
+
description: params.description
|
|
456
|
+
}
|
|
457
|
+
};
|
|
458
|
+
};
|
|
459
|
+
var validateFileEditParams = (params) => {
|
|
460
|
+
const errors = [];
|
|
461
|
+
if (!params.file_path || typeof params.file_path !== "string") {
|
|
462
|
+
errors.push('Required parameter "file_path" must be a non-empty string');
|
|
463
|
+
}
|
|
464
|
+
if (!params.old_text || typeof params.old_text !== "string") {
|
|
465
|
+
errors.push('Required parameter "old_text" must be a string');
|
|
466
|
+
}
|
|
467
|
+
if (params.new_text === void 0 || typeof params.new_text !== "string") {
|
|
468
|
+
errors.push('Required parameter "new_text" must be a string');
|
|
469
|
+
}
|
|
470
|
+
if (params.dry_run !== void 0 && typeof params.dry_run !== "boolean") {
|
|
471
|
+
errors.push('Parameter "dry_run" must be a boolean');
|
|
472
|
+
}
|
|
473
|
+
if (params.description !== void 0 && typeof params.description !== "string") {
|
|
474
|
+
errors.push('Parameter "description" must be a string');
|
|
475
|
+
}
|
|
476
|
+
if (errors.length > 0) {
|
|
477
|
+
return { valid: false, errors };
|
|
478
|
+
}
|
|
479
|
+
return {
|
|
480
|
+
valid: true,
|
|
481
|
+
data: {
|
|
482
|
+
file_path: params.file_path,
|
|
483
|
+
old_text: params.old_text,
|
|
484
|
+
new_text: params.new_text,
|
|
485
|
+
dry_run: params.dry_run,
|
|
486
|
+
description: params.description
|
|
487
|
+
}
|
|
488
|
+
};
|
|
489
|
+
};
|
|
490
|
+
var validateFileNewParams = (params) => {
|
|
491
|
+
const errors = [];
|
|
492
|
+
if (!params.file_path || typeof params.file_path !== "string") {
|
|
493
|
+
errors.push('Required parameter "file_path" must be a non-empty string');
|
|
494
|
+
}
|
|
495
|
+
if (params.content === void 0 || typeof params.content !== "string") {
|
|
496
|
+
errors.push('Required parameter "content" must be a string');
|
|
497
|
+
}
|
|
498
|
+
if (params.description !== void 0 && typeof params.description !== "string") {
|
|
499
|
+
errors.push('Parameter "description" must be a string');
|
|
500
|
+
}
|
|
501
|
+
if (errors.length > 0) {
|
|
502
|
+
return { valid: false, errors };
|
|
503
|
+
}
|
|
504
|
+
return {
|
|
505
|
+
valid: true,
|
|
506
|
+
data: {
|
|
507
|
+
file_path: params.file_path,
|
|
508
|
+
content: params.content,
|
|
509
|
+
description: params.description
|
|
510
|
+
}
|
|
511
|
+
};
|
|
512
|
+
};
|
|
513
|
+
var validateDirLsParams = (params) => {
|
|
514
|
+
const errors = [];
|
|
515
|
+
if (params.path !== void 0 && typeof params.path !== "string") {
|
|
516
|
+
errors.push('Parameter "path" must be a string');
|
|
517
|
+
}
|
|
518
|
+
if (params.limit !== void 0) {
|
|
519
|
+
if (typeof params.limit !== "number" || params.limit < 1) {
|
|
520
|
+
errors.push('Parameter "limit" must be a positive integer');
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
if (params.description !== void 0 && typeof params.description !== "string") {
|
|
524
|
+
errors.push('Parameter "description" must be a string');
|
|
525
|
+
}
|
|
526
|
+
if (errors.length > 0) {
|
|
527
|
+
return { valid: false, errors };
|
|
528
|
+
}
|
|
529
|
+
return {
|
|
530
|
+
valid: true,
|
|
531
|
+
data: {
|
|
532
|
+
path: params.path,
|
|
533
|
+
limit: params.limit,
|
|
534
|
+
description: params.description
|
|
535
|
+
}
|
|
536
|
+
};
|
|
537
|
+
};
|
|
538
|
+
var validateWebSearchParams = (params) => {
|
|
539
|
+
const errors = [];
|
|
540
|
+
if (!params.query || typeof params.query !== "string") {
|
|
541
|
+
errors.push('Required parameter "query" must be a non-empty string');
|
|
542
|
+
}
|
|
543
|
+
if (params.count !== void 0) {
|
|
544
|
+
if (typeof params.count !== "number" || params.count < 1 || params.count > 50) {
|
|
545
|
+
errors.push('Parameter "count" must be a number between 1 and 50');
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
if (params.offset !== void 0) {
|
|
549
|
+
if (typeof params.offset !== "number" || params.offset < 0) {
|
|
550
|
+
errors.push('Parameter "offset" must be a non-negative number');
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
if (params.domains !== void 0) {
|
|
554
|
+
if (!Array.isArray(params.domains) || !params.domains.every((d) => typeof d === "string")) {
|
|
555
|
+
errors.push('Parameter "domains" must be an array of strings');
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
if (params.recencyDays !== void 0) {
|
|
559
|
+
if (typeof params.recencyDays !== "number" || params.recencyDays < 1) {
|
|
560
|
+
errors.push('Parameter "recencyDays" must be a positive number');
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
if (params.lang !== void 0 && typeof params.lang !== "string") {
|
|
564
|
+
errors.push('Parameter "lang" must be a string');
|
|
565
|
+
}
|
|
566
|
+
if (params.region !== void 0 && typeof params.region !== "string") {
|
|
567
|
+
errors.push('Parameter "region" must be a string');
|
|
568
|
+
}
|
|
569
|
+
if (params.safe !== void 0 && typeof params.safe !== "boolean") {
|
|
570
|
+
errors.push('Parameter "safe" must be a boolean');
|
|
571
|
+
}
|
|
572
|
+
if (params.type !== void 0) {
|
|
573
|
+
if (params.type !== "web" && params.type !== "images") {
|
|
574
|
+
errors.push('Parameter "type" must be either "web" or "images"');
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
if (params.hydrateMeta !== void 0 && typeof params.hydrateMeta !== "boolean") {
|
|
578
|
+
errors.push('Parameter "hydrateMeta" must be a boolean');
|
|
579
|
+
}
|
|
580
|
+
if (params.description !== void 0 && typeof params.description !== "string") {
|
|
581
|
+
errors.push('Parameter "description" must be a string');
|
|
582
|
+
}
|
|
583
|
+
if (errors.length > 0) {
|
|
584
|
+
return { valid: false, errors };
|
|
585
|
+
}
|
|
586
|
+
return {
|
|
587
|
+
valid: true,
|
|
588
|
+
data: {
|
|
589
|
+
query: params.query,
|
|
590
|
+
count: params.count,
|
|
591
|
+
offset: params.offset,
|
|
592
|
+
domains: params.domains,
|
|
593
|
+
recencyDays: params.recencyDays,
|
|
594
|
+
lang: params.lang,
|
|
595
|
+
region: params.region,
|
|
596
|
+
safe: params.safe,
|
|
597
|
+
type: params.type,
|
|
598
|
+
hydrateMeta: params.hydrateMeta,
|
|
599
|
+
description: params.description
|
|
600
|
+
}
|
|
601
|
+
};
|
|
602
|
+
};
|
|
603
|
+
var validateWebFetchParams = (params) => {
|
|
604
|
+
const errors = [];
|
|
605
|
+
if (!params.url || typeof params.url !== "string") {
|
|
606
|
+
errors.push('Required parameter "url" must be a non-empty string');
|
|
607
|
+
}
|
|
608
|
+
if (params.description !== void 0 && typeof params.description !== "string") {
|
|
609
|
+
errors.push('Parameter "description" must be a string');
|
|
610
|
+
}
|
|
611
|
+
if (errors.length > 0) {
|
|
612
|
+
return { valid: false, errors };
|
|
613
|
+
}
|
|
614
|
+
return {
|
|
615
|
+
valid: true,
|
|
616
|
+
data: {
|
|
617
|
+
url: params.url,
|
|
618
|
+
description: params.description
|
|
619
|
+
}
|
|
620
|
+
};
|
|
621
|
+
};
|
|
622
|
+
var validateTodoWriteParams = (params) => {
|
|
623
|
+
const errors = [];
|
|
624
|
+
if (!params.todos || !Array.isArray(params.todos)) {
|
|
625
|
+
errors.push('Required parameter "todos" must be an array');
|
|
626
|
+
} else {
|
|
627
|
+
for (let i = 0; i < params.todos.length; i++) {
|
|
628
|
+
const todo = params.todos[i];
|
|
629
|
+
if (typeof todo !== "object" || todo === null) {
|
|
630
|
+
errors.push(`todos[${i}] must be an object`);
|
|
631
|
+
continue;
|
|
632
|
+
}
|
|
633
|
+
if (!todo.id || typeof todo.id !== "string") {
|
|
634
|
+
errors.push(`todos[${i}].id must be a non-empty string`);
|
|
635
|
+
}
|
|
636
|
+
if (!todo.content || typeof todo.content !== "string") {
|
|
637
|
+
errors.push(`todos[${i}].content must be a non-empty string`);
|
|
638
|
+
}
|
|
639
|
+
if (!todo.status || !["pending", "in_progress", "completed"].includes(todo.status)) {
|
|
640
|
+
errors.push(`todos[${i}].status must be one of: pending, in_progress, completed`);
|
|
641
|
+
}
|
|
642
|
+
if (!todo.priority || !["high", "medium", "low"].includes(todo.priority)) {
|
|
643
|
+
errors.push(`todos[${i}].priority must be one of: high, medium, low`);
|
|
644
|
+
}
|
|
645
|
+
if (todo.createdAt !== void 0 && typeof todo.createdAt !== "string") {
|
|
646
|
+
errors.push(`todos[${i}].createdAt must be a string`);
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
if (params.description !== void 0 && typeof params.description !== "string") {
|
|
651
|
+
errors.push('Parameter "description" must be a string');
|
|
652
|
+
}
|
|
653
|
+
if (errors.length > 0) {
|
|
654
|
+
return { valid: false, errors };
|
|
655
|
+
}
|
|
656
|
+
return {
|
|
657
|
+
valid: true,
|
|
658
|
+
data: {
|
|
659
|
+
todos: params.todos,
|
|
660
|
+
description: params.description
|
|
661
|
+
}
|
|
662
|
+
};
|
|
663
|
+
};
|
|
664
|
+
var validateAssignTaskParams = (params) => {
|
|
665
|
+
const errors = [];
|
|
666
|
+
if (!params.agent || typeof params.agent !== "string") {
|
|
667
|
+
errors.push('Required parameter "agent" must be a non-empty string');
|
|
668
|
+
}
|
|
669
|
+
if (!params.task || typeof params.task !== "string") {
|
|
670
|
+
errors.push('Required parameter "task" must be a non-empty string');
|
|
671
|
+
}
|
|
672
|
+
if (!params.description || typeof params.description !== "string") {
|
|
673
|
+
errors.push('Required parameter "description" must be a non-empty string');
|
|
674
|
+
}
|
|
675
|
+
if (errors.length > 0) {
|
|
676
|
+
return { valid: false, errors };
|
|
677
|
+
}
|
|
678
|
+
return {
|
|
679
|
+
valid: true,
|
|
680
|
+
data: {
|
|
681
|
+
agent: params.agent,
|
|
682
|
+
task: params.task,
|
|
683
|
+
description: params.description
|
|
684
|
+
}
|
|
685
|
+
};
|
|
686
|
+
};
|
|
687
|
+
var toolValidators = {
|
|
688
|
+
bash_tool: validateBashToolParams,
|
|
689
|
+
file_read: validateFileReadParams,
|
|
690
|
+
file_edit: validateFileEditParams,
|
|
691
|
+
file_new: validateFileNewParams,
|
|
692
|
+
dir_ls: validateDirLsParams,
|
|
693
|
+
web_search: validateWebSearchParams,
|
|
694
|
+
web_fetch: validateWebFetchParams,
|
|
695
|
+
todo_write: validateTodoWriteParams,
|
|
696
|
+
assign_task: validateAssignTaskParams
|
|
697
|
+
};
|
|
698
|
+
|
|
699
|
+
// src/tools/tool-call-converter.ts
|
|
700
|
+
function convertToolCall(toolCall, options = {}) {
|
|
701
|
+
const { strict = false } = options;
|
|
702
|
+
const parseResult = parseJSON(toolCall.function.arguments);
|
|
703
|
+
if (!parseResult.success) {
|
|
704
|
+
return {
|
|
705
|
+
valid: false,
|
|
706
|
+
error: parseResult.error,
|
|
707
|
+
errorType: "parse",
|
|
708
|
+
callId: toolCall.id,
|
|
709
|
+
toolName: toolCall.function.name,
|
|
710
|
+
rawArguments: toolCall.function.arguments
|
|
711
|
+
};
|
|
712
|
+
}
|
|
713
|
+
const toolName = toolCall.function.name;
|
|
714
|
+
const parameters = parseResult.data;
|
|
715
|
+
const validator = toolValidators[toolName];
|
|
716
|
+
if (validator) {
|
|
717
|
+
const validationResult = validator(parameters);
|
|
718
|
+
if (!validationResult.valid) {
|
|
719
|
+
if (strict) {
|
|
720
|
+
return {
|
|
721
|
+
valid: false,
|
|
722
|
+
error: `Validation failed: ${validationResult.errors.join("; ")}`,
|
|
723
|
+
errorType: "validation",
|
|
724
|
+
callId: toolCall.id,
|
|
725
|
+
toolName: toolCall.function.name,
|
|
726
|
+
rawArguments: toolCall.function.arguments
|
|
727
|
+
};
|
|
728
|
+
}
|
|
729
|
+
console.warn(`[ToolCallConverter] Validation warnings for ${toolName}:`, validationResult.errors);
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
return {
|
|
733
|
+
valid: true,
|
|
734
|
+
invocation: {
|
|
735
|
+
id: toolCall.id,
|
|
736
|
+
name: toolCall.function.name,
|
|
737
|
+
parameters
|
|
738
|
+
}
|
|
739
|
+
};
|
|
740
|
+
}
|
|
741
|
+
function convertToolCalls(toolCalls, options = {}) {
|
|
742
|
+
const { strict = false, throwOnError = true } = options;
|
|
743
|
+
const invocations = [];
|
|
744
|
+
for (const tc of toolCalls) {
|
|
745
|
+
const result = convertToolCall(tc, { strict });
|
|
746
|
+
if (!result.valid) {
|
|
747
|
+
const errorMsg = `Tool call ${result.callId} (${result.toolName}): ${result.error}`;
|
|
748
|
+
if (throwOnError) {
|
|
749
|
+
throw new Error(errorMsg);
|
|
750
|
+
}
|
|
751
|
+
console.error(`[ToolCallConverter] ${errorMsg}`);
|
|
752
|
+
invocations.push({
|
|
753
|
+
id: result.callId,
|
|
754
|
+
name: result.toolName,
|
|
755
|
+
parameters: {}
|
|
756
|
+
});
|
|
757
|
+
} else {
|
|
758
|
+
invocations.push(result.invocation);
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
return invocations;
|
|
762
|
+
}
|
|
763
|
+
|
|
378
764
|
// src/orchestrator.ts
|
|
379
765
|
var removeAttachmentTokens = (value, attachments) => {
|
|
380
766
|
return attachments.reduce((acc, attachment) => {
|
|
@@ -812,7 +1198,14 @@ var AgentOrchestrator = class {
|
|
|
812
1198
|
};
|
|
813
1199
|
const toolResultMsgs = [];
|
|
814
1200
|
for (const tr of toolResults) {
|
|
815
|
-
|
|
1201
|
+
let contentStr;
|
|
1202
|
+
if (tr.status === "error") {
|
|
1203
|
+
contentStr = tr.result;
|
|
1204
|
+
} else if (tr.type === "text") {
|
|
1205
|
+
contentStr = tr.result;
|
|
1206
|
+
} else {
|
|
1207
|
+
contentStr = JSON.stringify(tr.result, null, 2);
|
|
1208
|
+
}
|
|
816
1209
|
toolResultMsgs.push({
|
|
817
1210
|
id: tr.id,
|
|
818
1211
|
role: "tool",
|
|
@@ -838,7 +1231,14 @@ var AgentOrchestrator = class {
|
|
|
838
1231
|
tool_calls: approvedCalls
|
|
839
1232
|
});
|
|
840
1233
|
for (const tr of toolResults) {
|
|
841
|
-
|
|
1234
|
+
let contentStr;
|
|
1235
|
+
if (tr.status === "error") {
|
|
1236
|
+
contentStr = tr.result;
|
|
1237
|
+
} else if (tr.type === "text") {
|
|
1238
|
+
contentStr = tr.result;
|
|
1239
|
+
} else {
|
|
1240
|
+
contentStr = JSON.stringify(tr.result, null, 2);
|
|
1241
|
+
}
|
|
842
1242
|
accumulatedMessages.push({ role: "tool", content: contentStr, tool_call_id: tr.id, name: tr.name });
|
|
843
1243
|
}
|
|
844
1244
|
if (opts.signal?.aborted) throw new Error("Aborted");
|
|
@@ -978,14 +1378,9 @@ var AgentOrchestrator = class {
|
|
|
978
1378
|
}
|
|
979
1379
|
}
|
|
980
1380
|
toInvocations(toolCalls) {
|
|
981
|
-
return toolCalls
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
parameters = JSON.parse(tc.function.arguments || "{}");
|
|
985
|
-
} catch {
|
|
986
|
-
parameters = {};
|
|
987
|
-
}
|
|
988
|
-
return { id: tc.id, name: tc.function.name, parameters };
|
|
1381
|
+
return convertToolCalls(toolCalls, {
|
|
1382
|
+
strict: this.cfg.strictToolValidation ?? false,
|
|
1383
|
+
throwOnError: true
|
|
989
1384
|
});
|
|
990
1385
|
}
|
|
991
1386
|
};
|
|
@@ -1543,6 +1938,18 @@ var TodoStore = class {
|
|
|
1543
1938
|
}
|
|
1544
1939
|
};
|
|
1545
1940
|
|
|
1941
|
+
// src/tools/result-helpers.ts
|
|
1942
|
+
function okText(result, metadata) {
|
|
1943
|
+
return { status: "success", type: "text", result, metadata };
|
|
1944
|
+
}
|
|
1945
|
+
function okJson(result, metadata) {
|
|
1946
|
+
return { status: "success", type: "json", result, metadata };
|
|
1947
|
+
}
|
|
1948
|
+
function err(result, metadata, errorReason) {
|
|
1949
|
+
const finalMetadata = errorReason ? { ...metadata, errorReason } : metadata;
|
|
1950
|
+
return { status: "error", type: "text", result, metadata: finalMetadata };
|
|
1951
|
+
}
|
|
1952
|
+
|
|
1546
1953
|
// src/tools/TodoWriteTool.ts
|
|
1547
1954
|
var TodoWriteTool = class {
|
|
1548
1955
|
constructor(store) {
|
|
@@ -1634,28 +2041,28 @@ When in doubt, use this tool. Being proactive with task management demonstrates
|
|
|
1634
2041
|
const todos = params?.todos;
|
|
1635
2042
|
const ctx = context;
|
|
1636
2043
|
if (!Array.isArray(todos) || todos.length === 0) {
|
|
1637
|
-
return
|
|
2044
|
+
return err('Parameter "todos" must be a non-empty array', void 0, "invalid_input" /* InvalidInput */);
|
|
1638
2045
|
}
|
|
1639
2046
|
for (let i = 0; i < todos.length; i++) {
|
|
1640
2047
|
const t = todos[i];
|
|
1641
2048
|
if (!t) continue;
|
|
1642
2049
|
if (!t.content || typeof t.content !== "string" || !t.content.trim()) {
|
|
1643
|
-
return
|
|
2050
|
+
return err(`Todo ${i + 1}: content required`, void 0, "invalid_input" /* InvalidInput */);
|
|
1644
2051
|
}
|
|
1645
2052
|
if (!["pending", "in_progress", "completed"].includes(String(t.status))) {
|
|
1646
|
-
return
|
|
2053
|
+
return err(`Todo ${i + 1}: invalid status`, void 0, "invalid_input" /* InvalidInput */);
|
|
1647
2054
|
}
|
|
1648
2055
|
if (!["high", "medium", "low"].includes(String(t.priority))) {
|
|
1649
|
-
return
|
|
2056
|
+
return err(`Todo ${i + 1}: invalid priority`, void 0, "invalid_input" /* InvalidInput */);
|
|
1650
2057
|
}
|
|
1651
2058
|
if (!t.id || typeof t.id !== "string" || !t.id.trim()) {
|
|
1652
|
-
return
|
|
2059
|
+
return err(`Todo ${i + 1}: id required`, void 0, "invalid_input" /* InvalidInput */);
|
|
1653
2060
|
}
|
|
1654
2061
|
}
|
|
1655
2062
|
const ids = todos.map((t) => t.id);
|
|
1656
2063
|
const unique = new Set(ids);
|
|
1657
2064
|
if (unique.size !== ids.length) {
|
|
1658
|
-
return
|
|
2065
|
+
return err("Todo items must have unique IDs", void 0, "invalid_input" /* InvalidInput */);
|
|
1659
2066
|
}
|
|
1660
2067
|
const conversationId = ctx?.sessionId || ctx?.conversationId || "default";
|
|
1661
2068
|
const nowIso = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -1694,17 +2101,13 @@ All todo items are now completed! Ask about next steps. Completed list:
|
|
|
1694
2101
|
Your todo list has changed. DO NOT mention this explicitly to the user. Latest contents:
|
|
1695
2102
|
[${serialized}].
|
|
1696
2103
|
</system-reminder>`;
|
|
1697
|
-
return {
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
progress: `${progress}%`,
|
|
1705
|
-
allCompleted
|
|
1706
|
-
}
|
|
1707
|
-
};
|
|
2104
|
+
return okText(systemReminder, {
|
|
2105
|
+
recentChanges: true,
|
|
2106
|
+
stats,
|
|
2107
|
+
progress: `${progress}%`,
|
|
2108
|
+
allCompleted,
|
|
2109
|
+
conversationId
|
|
2110
|
+
});
|
|
1708
2111
|
}
|
|
1709
2112
|
};
|
|
1710
2113
|
|
|
@@ -1919,21 +2322,35 @@ var WebSearchTool = class {
|
|
|
1919
2322
|
};
|
|
1920
2323
|
}
|
|
1921
2324
|
provider = new GoogleCseProvider();
|
|
2325
|
+
/**
|
|
2326
|
+
* Execute web search using Google Programmable Search Engine
|
|
2327
|
+
*
|
|
2328
|
+
* @param params - Search query and optional filters (domains, recency, language, region)
|
|
2329
|
+
* @param ctx - Execution context with optional abort signal
|
|
2330
|
+
* @returns Structured JSON with search results including title, URL, snippet, and metadata
|
|
2331
|
+
*
|
|
2332
|
+
* @example
|
|
2333
|
+
* ```typescript
|
|
2334
|
+
* const result = await webSearchTool.execute({
|
|
2335
|
+
* query: 'TypeScript discriminated unions',
|
|
2336
|
+
* count: 10,
|
|
2337
|
+
* lang: 'en'
|
|
2338
|
+
* });
|
|
2339
|
+
* if (result.status === 'success' && result.type === 'json') {
|
|
2340
|
+
* console.log(result.result.count); // number of results
|
|
2341
|
+
* result.result.items.forEach(item => {
|
|
2342
|
+
* console.log(`${item.title}: ${item.url}`);
|
|
2343
|
+
* });
|
|
2344
|
+
* }
|
|
2345
|
+
* ```
|
|
2346
|
+
*/
|
|
1922
2347
|
async execute(params, ctx) {
|
|
1923
2348
|
if (ctx?.signal?.aborted) {
|
|
1924
|
-
return
|
|
1925
|
-
type: "text",
|
|
1926
|
-
status: "error",
|
|
1927
|
-
result: "Search aborted by user"
|
|
1928
|
-
};
|
|
2349
|
+
return err("Search aborted by user", void 0, "aborted" /* Aborted */);
|
|
1929
2350
|
}
|
|
1930
2351
|
const query = typeof params.query === "string" ? params.query : "";
|
|
1931
2352
|
if (!query) {
|
|
1932
|
-
return
|
|
1933
|
-
type: "text",
|
|
1934
|
-
status: "error",
|
|
1935
|
-
result: "Missing required parameter: query"
|
|
1936
|
-
};
|
|
2353
|
+
return err("Missing required parameter: query", void 0, "invalid_input" /* InvalidInput */);
|
|
1937
2354
|
}
|
|
1938
2355
|
const p = {
|
|
1939
2356
|
query: String(params.query ?? "").trim(),
|
|
@@ -1948,14 +2365,10 @@ var WebSearchTool = class {
|
|
|
1948
2365
|
hydrateMeta: params.hydrateMeta ?? false
|
|
1949
2366
|
};
|
|
1950
2367
|
if (!p.query) {
|
|
1951
|
-
return
|
|
2368
|
+
return err("Missing 'query'", void 0, "invalid_input" /* InvalidInput */);
|
|
1952
2369
|
}
|
|
1953
2370
|
if (!process.env.GOOGLE_CSE_KEY || !process.env.GOOGLE_CSE_CX) {
|
|
1954
|
-
return
|
|
1955
|
-
status: "error",
|
|
1956
|
-
type: "text",
|
|
1957
|
-
result: "GOOGLE_CSE_KEY and GOOGLE_CSE_CX are required for this tool (Google CSE only)."
|
|
1958
|
-
};
|
|
2371
|
+
return err("GOOGLE_CSE_KEY and GOOGLE_CSE_CX are required for this tool (Google CSE only).", void 0, "invalid_input" /* InvalidInput */);
|
|
1959
2372
|
}
|
|
1960
2373
|
try {
|
|
1961
2374
|
let results = await this.provider.search(p, ctx?.signal);
|
|
@@ -1969,23 +2382,30 @@ var WebSearchTool = class {
|
|
|
1969
2382
|
seen.add(k);
|
|
1970
2383
|
return true;
|
|
1971
2384
|
}).slice(0, p.count);
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
2385
|
+
const appliedFilters = {};
|
|
2386
|
+
if (p.domains.length > 0) appliedFilters.domains = p.domains;
|
|
2387
|
+
if (p.recencyDays > 0) appliedFilters.recencyDays = p.recencyDays;
|
|
2388
|
+
if (p.lang && p.lang !== "en") appliedFilters.lang = p.lang;
|
|
2389
|
+
if (p.region) appliedFilters.region = p.region;
|
|
2390
|
+
return okJson({
|
|
2391
|
+
engine: this.provider.name,
|
|
2392
|
+
count: results.length,
|
|
2393
|
+
items: results,
|
|
2394
|
+
query: p.query,
|
|
2395
|
+
appliedFilters: Object.keys(appliedFilters).length > 0 ? appliedFilters : void 0
|
|
2396
|
+
}, {
|
|
2397
|
+
offset: p.offset,
|
|
2398
|
+
totalRequested: p.count,
|
|
2399
|
+
hydrated: p.hydrateMeta
|
|
2400
|
+
});
|
|
1981
2401
|
} catch (error) {
|
|
1982
2402
|
const message = error instanceof Error ? error.message : String(error);
|
|
1983
2403
|
const isAborted = message.includes("aborted by user");
|
|
1984
|
-
return
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
2404
|
+
return err(
|
|
2405
|
+
isAborted ? "Search aborted by user" : message.slice(0, 500),
|
|
2406
|
+
void 0,
|
|
2407
|
+
isAborted ? "aborted" /* Aborted */ : "unknown" /* Unknown */
|
|
2408
|
+
);
|
|
1989
2409
|
}
|
|
1990
2410
|
}
|
|
1991
2411
|
};
|
|
@@ -2024,10 +2444,10 @@ var WebFetchTool = class {
|
|
|
2024
2444
|
async execute(params, ctx) {
|
|
2025
2445
|
const target = String(params.url ?? "");
|
|
2026
2446
|
if (!target) {
|
|
2027
|
-
return
|
|
2447
|
+
return err("URL parameter is required", void 0, "invalid_input" /* InvalidInput */);
|
|
2028
2448
|
}
|
|
2029
2449
|
if (ctx?.signal?.aborted) {
|
|
2030
|
-
return
|
|
2450
|
+
return err("Fetch aborted by user", void 0, "aborted" /* Aborted */);
|
|
2031
2451
|
}
|
|
2032
2452
|
try {
|
|
2033
2453
|
const res = await fetch(target, {
|
|
@@ -2037,33 +2457,41 @@ var WebFetchTool = class {
|
|
|
2037
2457
|
signal: ctx?.signal
|
|
2038
2458
|
});
|
|
2039
2459
|
if (!res.ok) {
|
|
2040
|
-
return {
|
|
2041
|
-
status: "error",
|
|
2042
|
-
type: "text",
|
|
2043
|
-
result: `HTTP ${res.status} ${res.statusText}`
|
|
2044
|
-
};
|
|
2460
|
+
return err(`HTTP ${res.status} ${res.statusText}`, { url: target }, "network_error" /* NetworkError */);
|
|
2045
2461
|
}
|
|
2046
2462
|
const contentType = res.headers.get("content-type") || "";
|
|
2047
2463
|
const text = await res.text();
|
|
2464
|
+
const fetchedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
2465
|
+
let finalText;
|
|
2466
|
+
let format;
|
|
2048
2467
|
if (contentType.includes("application/json")) {
|
|
2049
|
-
|
|
2468
|
+
finalText = `\`\`\`json
|
|
2050
2469
|
${text}
|
|
2051
2470
|
\`\`\``;
|
|
2052
|
-
|
|
2471
|
+
format = "json";
|
|
2053
2472
|
} else if (contentType.includes("text/html")) {
|
|
2054
|
-
|
|
2055
|
-
|
|
2473
|
+
finalText = this.turndownService.turndown(text);
|
|
2474
|
+
format = "markdown";
|
|
2056
2475
|
} else {
|
|
2057
|
-
|
|
2476
|
+
finalText = text;
|
|
2477
|
+
format = "text";
|
|
2058
2478
|
}
|
|
2479
|
+
return okText(finalText, {
|
|
2480
|
+
url: target,
|
|
2481
|
+
contentType,
|
|
2482
|
+
statusCode: res.status,
|
|
2483
|
+
format,
|
|
2484
|
+
size: text.length,
|
|
2485
|
+
fetchedAt
|
|
2486
|
+
});
|
|
2059
2487
|
} catch (error) {
|
|
2060
2488
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
2061
2489
|
const isAborted = errorMessage.includes("aborted") || error.name === "AbortError";
|
|
2062
|
-
return
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2490
|
+
return err(
|
|
2491
|
+
isAborted ? "Fetch aborted by user" : errorMessage,
|
|
2492
|
+
{ url: target },
|
|
2493
|
+
isAborted ? "aborted" /* Aborted */ : "network_error" /* NetworkError */
|
|
2494
|
+
);
|
|
2067
2495
|
}
|
|
2068
2496
|
}
|
|
2069
2497
|
};
|
|
@@ -2071,17 +2499,6 @@ ${text}
|
|
|
2071
2499
|
// src/tools/FileReadTool.ts
|
|
2072
2500
|
import { promises as fs3 } from "fs";
|
|
2073
2501
|
import * as path3 from "path";
|
|
2074
|
-
|
|
2075
|
-
// src/tools/result-helpers.ts
|
|
2076
|
-
function ok(result, metadata) {
|
|
2077
|
-
return { status: "success", type: "text", result, metadata };
|
|
2078
|
-
}
|
|
2079
|
-
function err(result, metadata, errorReason) {
|
|
2080
|
-
const finalMetadata = errorReason ? { ...metadata, errorReason } : metadata;
|
|
2081
|
-
return { status: "error", type: "text", result, metadata: finalMetadata };
|
|
2082
|
-
}
|
|
2083
|
-
|
|
2084
|
-
// src/tools/FileReadTool.ts
|
|
2085
2502
|
var FileReadTool = class {
|
|
2086
2503
|
name = "file_read";
|
|
2087
2504
|
rootDir;
|
|
@@ -2114,24 +2531,45 @@ var FileReadTool = class {
|
|
|
2114
2531
|
parameters: this.parameters
|
|
2115
2532
|
};
|
|
2116
2533
|
}
|
|
2534
|
+
/**
|
|
2535
|
+
* Read file contents with optional line range selection
|
|
2536
|
+
*
|
|
2537
|
+
* @param params - File path and optional line range (lineStart, lineEnd)
|
|
2538
|
+
* @param context - Execution context with optional workspace directory
|
|
2539
|
+
* @returns File content as text with metadata including path, size, and line range
|
|
2540
|
+
*
|
|
2541
|
+
* @example
|
|
2542
|
+
* ```typescript
|
|
2543
|
+
* const result = await fileReadTool.execute({ path: 'package.json' });
|
|
2544
|
+
* if (result.status === 'success' && result.type === 'text') {
|
|
2545
|
+
* console.log(result.result); // file contents
|
|
2546
|
+
* console.log(result.metadata?.path); // resolved file path
|
|
2547
|
+
* console.log(result.metadata?.size); // file size in bytes
|
|
2548
|
+
* }
|
|
2549
|
+
* ```
|
|
2550
|
+
*/
|
|
2117
2551
|
async execute(params, context) {
|
|
2118
2552
|
try {
|
|
2119
2553
|
if (!params.path || typeof params.path !== "string") {
|
|
2120
|
-
return err('Parameter "path" must be a non-empty string');
|
|
2554
|
+
return err('Parameter "path" must be a non-empty string', void 0, "invalid_input" /* InvalidInput */);
|
|
2121
2555
|
}
|
|
2122
2556
|
const abs = this.resolveSafePath(params.path, context);
|
|
2123
2557
|
const st = await fs3.stat(abs).catch(() => null);
|
|
2124
|
-
if (!st || !st.isFile()) return err(`File not found: ${params.path}
|
|
2558
|
+
if (!st || !st.isFile()) return err(`File not found: ${params.path}`, { path: params.path }, "not_found" /* NotFound */);
|
|
2125
2559
|
if (st.size > this.maxBytesHard) {
|
|
2126
|
-
return err(`File too large (${st.size} bytes). Hard cap is ${this.maxBytesHard} bytes
|
|
2560
|
+
return err(`File too large (${st.size} bytes). Hard cap is ${this.maxBytesHard} bytes.`, { path: params.path }, "invalid_input" /* InvalidInput */);
|
|
2127
2561
|
}
|
|
2128
2562
|
const payload = await fs3.readFile(abs);
|
|
2129
2563
|
let text = payload.toString("utf8");
|
|
2564
|
+
const bomStripped = text.charCodeAt(0) === 65279;
|
|
2130
2565
|
text = stripUtfBom(text);
|
|
2131
2566
|
const metadata = {
|
|
2132
2567
|
path: params.path,
|
|
2133
2568
|
created: st.birthtime.toISOString(),
|
|
2134
|
-
modified: st.mtime.toISOString()
|
|
2569
|
+
modified: st.mtime.toISOString(),
|
|
2570
|
+
size: st.size,
|
|
2571
|
+
encoding: "utf8",
|
|
2572
|
+
bomStripped
|
|
2135
2573
|
};
|
|
2136
2574
|
if (params.lineStart || params.lineEnd) {
|
|
2137
2575
|
const lines = text.split(/\r?\n/);
|
|
@@ -2144,17 +2582,19 @@ var FileReadTool = class {
|
|
|
2144
2582
|
return `${lineNum}\u2502${line}`;
|
|
2145
2583
|
});
|
|
2146
2584
|
const slice = numberedLines.join("\n");
|
|
2147
|
-
return
|
|
2585
|
+
return okText(slice, {
|
|
2148
2586
|
...metadata,
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2587
|
+
lineRange: {
|
|
2588
|
+
lineStart: lo,
|
|
2589
|
+
lineEnd: hi,
|
|
2590
|
+
linesTotal: totalLines
|
|
2591
|
+
}
|
|
2152
2592
|
});
|
|
2153
2593
|
}
|
|
2154
|
-
return
|
|
2594
|
+
return okText(text, metadata);
|
|
2155
2595
|
} catch (e) {
|
|
2156
2596
|
const message = e instanceof Error ? e.message : String(e);
|
|
2157
|
-
return err(message);
|
|
2597
|
+
return err(message, { path: params.path }, "unknown" /* Unknown */);
|
|
2158
2598
|
}
|
|
2159
2599
|
}
|
|
2160
2600
|
// ---------- helpers ----------
|
|
@@ -2209,16 +2649,22 @@ var FileNewTool = class {
|
|
|
2209
2649
|
}
|
|
2210
2650
|
async execute(p, ctx) {
|
|
2211
2651
|
try {
|
|
2212
|
-
if (!p.file_path?.trim()) return err('Parameter "file_path" is required.');
|
|
2213
|
-
if (typeof p.content !== "string") return err('"content" must be a string.');
|
|
2652
|
+
if (!p.file_path?.trim()) return err('Parameter "file_path" is required.', void 0, "invalid_input" /* InvalidInput */);
|
|
2653
|
+
if (typeof p.content !== "string") return err('"content" must be a string.', void 0, "invalid_input" /* InvalidInput */);
|
|
2214
2654
|
const abs = this.resolveSafePath(p.file_path, ctx);
|
|
2655
|
+
const existsBefore = await fs4.stat(abs).then(() => true).catch(() => false);
|
|
2215
2656
|
await fs4.mkdir(path4.dirname(abs), { recursive: true });
|
|
2216
2657
|
const bytes = Buffer.from(p.content, "utf8");
|
|
2217
2658
|
await this.writeAtomic(abs, bytes);
|
|
2218
|
-
return
|
|
2659
|
+
return okText(`File written at ${p.file_path}.`, {
|
|
2660
|
+
file_path: p.file_path,
|
|
2661
|
+
bytes: bytes.length,
|
|
2662
|
+
created: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2663
|
+
overwritten: existsBefore
|
|
2664
|
+
});
|
|
2219
2665
|
} catch (e) {
|
|
2220
2666
|
const message = e instanceof Error ? e.message : String(e);
|
|
2221
|
-
return err(message);
|
|
2667
|
+
return err(message, void 0, "unknown" /* Unknown */);
|
|
2222
2668
|
}
|
|
2223
2669
|
}
|
|
2224
2670
|
// helpers
|
|
@@ -2295,21 +2741,21 @@ var FileEditTool = class {
|
|
|
2295
2741
|
}
|
|
2296
2742
|
async execute(p, ctx) {
|
|
2297
2743
|
try {
|
|
2298
|
-
if (!p.file_path?.trim()) return err('Parameter "file_path" is required.');
|
|
2744
|
+
if (!p.file_path?.trim()) return err('Parameter "file_path" is required.', void 0, "invalid_input" /* InvalidInput */);
|
|
2299
2745
|
const abs = resolveAbsoluteWithinRoot(p.file_path, ctx, this.rootDir);
|
|
2300
2746
|
if (typeof p.old_text !== "string") {
|
|
2301
|
-
return err("old_text must be a string.");
|
|
2747
|
+
return err("old_text must be a string.", void 0, "invalid_input" /* InvalidInput */);
|
|
2302
2748
|
}
|
|
2303
2749
|
if (typeof p.new_text !== "string") {
|
|
2304
|
-
return err("new_text must be a string.");
|
|
2750
|
+
return err("new_text must be a string.", void 0, "invalid_input" /* InvalidInput */);
|
|
2305
2751
|
}
|
|
2306
2752
|
const st = await fs5.stat(abs).catch(() => null);
|
|
2307
2753
|
const exists = !!st && st.isFile();
|
|
2308
2754
|
if (!exists || !st) {
|
|
2309
|
-
return err("File does not exist. Use a file creation tool to create new files.");
|
|
2755
|
+
return err("File does not exist. Use a file creation tool to create new files.", void 0, "not_found" /* NotFound */);
|
|
2310
2756
|
}
|
|
2311
2757
|
if (st.size > this.maxBytes) {
|
|
2312
|
-
return err(`File too large (${st.size} bytes). Cap is ${this.maxBytes}
|
|
2758
|
+
return err(`File too large (${st.size} bytes). Cap is ${this.maxBytes}.`, void 0, "invalid_input" /* InvalidInput */);
|
|
2313
2759
|
}
|
|
2314
2760
|
const originalBytes = await fs5.readFile(abs);
|
|
2315
2761
|
const originalEol = detectEol(originalBytes) ?? "lf";
|
|
@@ -2322,14 +2768,16 @@ var FileEditTool = class {
|
|
|
2322
2768
|
const preview = oldTextLF.slice(0, 100).replace(/\n/g, "\\n");
|
|
2323
2769
|
return err(
|
|
2324
2770
|
`old_text not found in file. Make sure it matches exactly including whitespace.
|
|
2325
|
-
Searching for: "${preview}${oldTextLF.length > 100 ? "..." : ""}"
|
|
2771
|
+
Searching for: "${preview}${oldTextLF.length > 100 ? "..." : ""}"`,
|
|
2772
|
+
void 0,
|
|
2773
|
+
"not_found" /* NotFound */
|
|
2326
2774
|
);
|
|
2327
2775
|
}
|
|
2328
2776
|
const resultLF = originalLF.slice(0, idx) + newTextLF + originalLF.slice(idx + oldTextLF.length);
|
|
2329
2777
|
const finalText = convertEol(resultLF, originalEol);
|
|
2330
2778
|
const finalBytes = Buffer.from(finalText, "utf8");
|
|
2331
2779
|
if (finalBytes.length > this.maxBytes) {
|
|
2332
|
-
return err(`Resulting file too large (${finalBytes.length} bytes). Cap is ${this.maxBytes}
|
|
2780
|
+
return err(`Resulting file too large (${finalBytes.length} bytes). Cap is ${this.maxBytes}.`, void 0, "invalid_input" /* InvalidInput */);
|
|
2333
2781
|
}
|
|
2334
2782
|
const beforeSha = sha256(originalBytes);
|
|
2335
2783
|
const afterSha = sha256(finalBytes);
|
|
@@ -2338,10 +2786,13 @@ Searching for: "${preview}${oldTextLF.length > 100 ? "..." : ""}"`
|
|
|
2338
2786
|
await atomicWrite(abs, finalBytes);
|
|
2339
2787
|
}
|
|
2340
2788
|
const lineNumbers = this.calculateLineNumbers(originalLF, oldTextLF, newTextLF, idx);
|
|
2341
|
-
return
|
|
2789
|
+
return okText(
|
|
2342
2790
|
noChange ? "No changes (content identical)." : p.dry_run ? "Validated (dry run: no write)." : "Edit applied successfully.",
|
|
2343
2791
|
{
|
|
2344
2792
|
path: showPath(abs, this.rootDir),
|
|
2793
|
+
created: st.birthtime.toISOString(),
|
|
2794
|
+
modified: st.mtime.toISOString(),
|
|
2795
|
+
size: st.size,
|
|
2345
2796
|
eol: originalEol,
|
|
2346
2797
|
oldTextLength: oldTextLF.length,
|
|
2347
2798
|
newTextLength: newTextLF.length,
|
|
@@ -2349,11 +2800,12 @@ Searching for: "${preview}${oldTextLF.length > 100 ? "..." : ""}"`
|
|
|
2349
2800
|
beforeSha,
|
|
2350
2801
|
afterSha,
|
|
2351
2802
|
dryRun: !!p.dry_run,
|
|
2352
|
-
lineNumbers
|
|
2803
|
+
lineNumbers,
|
|
2804
|
+
noChange
|
|
2353
2805
|
}
|
|
2354
2806
|
);
|
|
2355
2807
|
} catch (e) {
|
|
2356
|
-
return err(e instanceof Error ? e.message : String(e));
|
|
2808
|
+
return err(e instanceof Error ? e.message : String(e), void 0, "unknown" /* Unknown */);
|
|
2357
2809
|
}
|
|
2358
2810
|
}
|
|
2359
2811
|
calculateLineNumbers(originalText, oldText, newText, matchIndex) {
|
|
@@ -2500,6 +2952,23 @@ var BashTool = class {
|
|
|
2500
2952
|
parameters: this.parameters
|
|
2501
2953
|
};
|
|
2502
2954
|
}
|
|
2955
|
+
/**
|
|
2956
|
+
* Execute bash command with timeout protection
|
|
2957
|
+
*
|
|
2958
|
+
* @param p - Command parameters including cmd, cwd, and optional timeout
|
|
2959
|
+
* @param ctx - Execution context with optional abort signal
|
|
2960
|
+
* @returns Structured result with command output and execution metadata
|
|
2961
|
+
*
|
|
2962
|
+
* @example
|
|
2963
|
+
* ```typescript
|
|
2964
|
+
* const result = await bashTool.execute({ cmd: 'ls -la' });
|
|
2965
|
+
* if (result.status === 'success' && result.type === 'text') {
|
|
2966
|
+
* console.log(result.result); // command output
|
|
2967
|
+
* console.log(result.metadata?.code); // exit code
|
|
2968
|
+
* console.log(result.metadata?.cwd); // working directory
|
|
2969
|
+
* }
|
|
2970
|
+
* ```
|
|
2971
|
+
*/
|
|
2503
2972
|
async execute(p, ctx) {
|
|
2504
2973
|
try {
|
|
2505
2974
|
return await this.execOnce(p, ctx?.signal);
|
|
@@ -2618,7 +3087,7 @@ ${output}` : "";
|
|
|
2618
3087
|
}
|
|
2619
3088
|
return err(output, metadata);
|
|
2620
3089
|
}
|
|
2621
|
-
return
|
|
3090
|
+
return okText(output, { code, signal: exitSignal, cwd, stripped: stripAnsi });
|
|
2622
3091
|
} catch (e) {
|
|
2623
3092
|
if (timer) clearTimeout(timer);
|
|
2624
3093
|
const message = e instanceof Error ? e.message : String(e);
|
|
@@ -2701,7 +3170,7 @@ var DirLsTool = class {
|
|
|
2701
3170
|
name: this.name,
|
|
2702
3171
|
description: [
|
|
2703
3172
|
"List files and directories in a specified directory.",
|
|
2704
|
-
"Returns entries sorted alphabetically by name
|
|
3173
|
+
"Returns entries sorted alphabetically by name as structured JSON.",
|
|
2705
3174
|
"",
|
|
2706
3175
|
"Typical uses:",
|
|
2707
3176
|
"1) List all files in current directory",
|
|
@@ -2733,6 +3202,25 @@ var DirLsTool = class {
|
|
|
2733
3202
|
return 0;
|
|
2734
3203
|
}
|
|
2735
3204
|
}
|
|
3205
|
+
/**
|
|
3206
|
+
* List directory contents as structured JSON
|
|
3207
|
+
*
|
|
3208
|
+
* @param params - Directory path and optional limit
|
|
3209
|
+
* @param context - Execution context with optional workspace directory
|
|
3210
|
+
* @returns Structured JSON with directory entries including name, type, size, and metadata
|
|
3211
|
+
*
|
|
3212
|
+
* @example
|
|
3213
|
+
* ```typescript
|
|
3214
|
+
* const result = await dirLsTool.execute({ path: 'src/tools', limit: 50 });
|
|
3215
|
+
* if (result.status === 'success' && result.type === 'json') {
|
|
3216
|
+
* console.log(result.result.path); // 'src/tools'
|
|
3217
|
+
* console.log(result.result.total); // number of entries
|
|
3218
|
+
* result.result.entries.forEach(entry => {
|
|
3219
|
+
* console.log(`${entry.name} (${entry.type}): ${entry.size} bytes`);
|
|
3220
|
+
* });
|
|
3221
|
+
* }
|
|
3222
|
+
* ```
|
|
3223
|
+
*/
|
|
2736
3224
|
async execute(params, context) {
|
|
2737
3225
|
try {
|
|
2738
3226
|
const targetPath = params.path ?? ".";
|
|
@@ -2741,10 +3229,10 @@ var DirLsTool = class {
|
|
|
2741
3229
|
const abs = this.resolveSafePath(targetPath, context);
|
|
2742
3230
|
const st = await fs7.stat(abs).catch(() => null);
|
|
2743
3231
|
if (!st) {
|
|
2744
|
-
return err(`Directory not found: ${targetPath}
|
|
3232
|
+
return err(`Directory not found: ${targetPath}`, void 0, "not_found" /* NotFound */);
|
|
2745
3233
|
}
|
|
2746
3234
|
if (!st.isDirectory()) {
|
|
2747
|
-
return err(`Path is not a directory: ${targetPath}
|
|
3235
|
+
return err(`Path is not a directory: ${targetPath}`, void 0, "invalid_input" /* InvalidInput */);
|
|
2748
3236
|
}
|
|
2749
3237
|
const entries = await fs7.readdir(abs);
|
|
2750
3238
|
const results = [];
|
|
@@ -2781,40 +3269,23 @@ var DirLsTool = class {
|
|
|
2781
3269
|
results.push(dirEntry);
|
|
2782
3270
|
}
|
|
2783
3271
|
results.sort((a, b) => a.name.localeCompare(b.name));
|
|
2784
|
-
const
|
|
2785
|
-
|
|
2786
|
-
|
|
3272
|
+
const result = okJson(
|
|
3273
|
+
{
|
|
3274
|
+
path: targetPath,
|
|
3275
|
+
entries: results,
|
|
3276
|
+
truncated: entries.length > limit,
|
|
3277
|
+
total: results.length
|
|
3278
|
+
},
|
|
3279
|
+
{
|
|
3280
|
+
limit,
|
|
3281
|
+
includeHidden
|
|
3282
|
+
}
|
|
3283
|
+
);
|
|
3284
|
+
return result;
|
|
2787
3285
|
} catch (e) {
|
|
2788
3286
|
const message = e instanceof Error ? e.message : String(e);
|
|
2789
|
-
return err(message);
|
|
2790
|
-
}
|
|
2791
|
-
}
|
|
2792
|
-
formatAsLsLine(entry) {
|
|
2793
|
-
const mode = entry.mode ? this.formatMode(entry.mode) : "----------";
|
|
2794
|
-
const size = entry.size !== void 0 ? entry.size.toString().padStart(10) : " 0";
|
|
2795
|
-
const date = entry.mtime ? new Date(entry.mtime) : /* @__PURE__ */ new Date();
|
|
2796
|
-
const month = date.toLocaleString("en-US", { month: "short" });
|
|
2797
|
-
const day = date.getDate().toString().padStart(2);
|
|
2798
|
-
const time = `${date.getHours().toString().padStart(2, "0")}:${date.getMinutes().toString().padStart(2, "0")}`;
|
|
2799
|
-
const dateStr = `${month} ${day} ${time}`;
|
|
2800
|
-
const typeIndicator = entry.type === "directory" ? "/" : entry.type === "symlink" ? "@" : "";
|
|
2801
|
-
const name = `${entry.name}${typeIndicator}`;
|
|
2802
|
-
return `${mode} ${size} ${dateStr} ${name}`;
|
|
2803
|
-
}
|
|
2804
|
-
formatMode(mode) {
|
|
2805
|
-
const fileType = (mode & 61440) === 16384 ? "d" : (mode & 61440) === 40960 ? "l" : "-";
|
|
2806
|
-
const perms = [
|
|
2807
|
-
mode & 256 ? "r" : "-",
|
|
2808
|
-
mode & 128 ? "w" : "-",
|
|
2809
|
-
mode & 64 ? "x" : "-",
|
|
2810
|
-
mode & 32 ? "r" : "-",
|
|
2811
|
-
mode & 16 ? "w" : "-",
|
|
2812
|
-
mode & 8 ? "x" : "-",
|
|
2813
|
-
mode & 4 ? "r" : "-",
|
|
2814
|
-
mode & 2 ? "w" : "-",
|
|
2815
|
-
mode & 1 ? "x" : "-"
|
|
2816
|
-
];
|
|
2817
|
-
return fileType + perms.join("");
|
|
3287
|
+
return err(message, void 0, "unknown" /* Unknown */);
|
|
3288
|
+
}
|
|
2818
3289
|
}
|
|
2819
3290
|
resolveSafePath(target, context) {
|
|
2820
3291
|
const baseFromCtx = context?.workspaceRoot || context?.cwd || this.rootDir;
|
|
@@ -2892,7 +3363,7 @@ var AgentRegistry = class {
|
|
|
2892
3363
|
systemPrompt: partial.systemPrompt,
|
|
2893
3364
|
tools,
|
|
2894
3365
|
temperature: partial.temperature ?? 0.7,
|
|
2895
|
-
maxTokens: partial.maxTokens ??
|
|
3366
|
+
maxTokens: partial.maxTokens ?? 64e3,
|
|
2896
3367
|
provider: partial.provider,
|
|
2897
3368
|
model: partial.model,
|
|
2898
3369
|
topP: partial.topP,
|
|
@@ -3084,20 +3555,55 @@ ${agentList}`,
|
|
|
3084
3555
|
};
|
|
3085
3556
|
}
|
|
3086
3557
|
/**
|
|
3087
|
-
*
|
|
3558
|
+
* Delegate a task to a specialist agent for focused execution
|
|
3559
|
+
*
|
|
3560
|
+
* @param params - Agent ID and task description to delegate
|
|
3561
|
+
* @param context - Execution context including delegation depth tracking
|
|
3562
|
+
* @returns Delegation result with comprehensive metrics including cost breakdown
|
|
3563
|
+
*
|
|
3564
|
+
* @example
|
|
3565
|
+
* ```typescript
|
|
3566
|
+
* const result = await assignTool.execute({
|
|
3567
|
+
* agent: 'code-reviewer',
|
|
3568
|
+
* task: 'Review the changes in src/tools/*.ts',
|
|
3569
|
+
* description: 'Code review of tool implementations'
|
|
3570
|
+
* });
|
|
3571
|
+
* if (result.status === 'success' && result.type === 'text') {
|
|
3572
|
+
* console.log(result.result); // Agent's response
|
|
3573
|
+
* console.log(result.metadata.metrics?.totalCost); // Cost in USD
|
|
3574
|
+
* console.log(result.metadata.executionTimeMs); // Duration
|
|
3575
|
+
* console.log(result.metadata.toolCallsExecuted); // Number of tool calls
|
|
3576
|
+
* }
|
|
3577
|
+
* ```
|
|
3088
3578
|
*/
|
|
3089
3579
|
async execute(params, context) {
|
|
3090
3580
|
if (!params.agent || typeof params.agent !== "string") {
|
|
3091
|
-
return err('Parameter "agent" is required and must be a string');
|
|
3581
|
+
return err('Parameter "agent" is required and must be a string', void 0, "invalid_input" /* InvalidInput */);
|
|
3092
3582
|
}
|
|
3093
3583
|
if (!params.task || typeof params.task !== "string") {
|
|
3094
|
-
return err('Parameter "task" is required and must be a string');
|
|
3584
|
+
return err('Parameter "task" is required and must be a string', void 0, "invalid_input" /* InvalidInput */);
|
|
3095
3585
|
}
|
|
3096
3586
|
const outcome = await this.delegationService.delegate(params, context);
|
|
3097
3587
|
if (!outcome.success || !outcome.summary) {
|
|
3098
|
-
|
|
3588
|
+
const isNotFound = outcome.error?.includes("not found");
|
|
3589
|
+
const isPolicyDenied = outcome.error?.includes("policy") || outcome.error?.includes("denied");
|
|
3590
|
+
return err(
|
|
3591
|
+
outcome.error ?? "Failed to delegate task.",
|
|
3592
|
+
{
|
|
3593
|
+
agentId: params.agent,
|
|
3594
|
+
agentNotFound: isNotFound,
|
|
3595
|
+
policyDenied: isPolicyDenied,
|
|
3596
|
+
delegationDepth: context?.delegationDepth
|
|
3597
|
+
},
|
|
3598
|
+
"unknown" /* Unknown */
|
|
3599
|
+
);
|
|
3099
3600
|
}
|
|
3100
|
-
|
|
3601
|
+
const metadata = outcome.metadata;
|
|
3602
|
+
return okText(outcome.summary, {
|
|
3603
|
+
...metadata,
|
|
3604
|
+
taskDescription: params.task,
|
|
3605
|
+
delegationDepth: (context?.delegationDepth ?? 0) + 1
|
|
3606
|
+
});
|
|
3101
3607
|
}
|
|
3102
3608
|
};
|
|
3103
3609
|
|
|
@@ -3224,6 +3730,7 @@ var AgentManager = class {
|
|
|
3224
3730
|
result: "Sub-agent execution aborted by user",
|
|
3225
3731
|
metadata: {
|
|
3226
3732
|
agentId,
|
|
3733
|
+
agentName: config.agentName,
|
|
3227
3734
|
toolCallsExecuted: 0,
|
|
3228
3735
|
executionTimeMs: 0,
|
|
3229
3736
|
errorMessage: "Aborted before execution"
|
|
@@ -3237,6 +3744,7 @@ var AgentManager = class {
|
|
|
3237
3744
|
result: `Maximum delegation depth (${MAX_DELEGATION_DEPTH}) exceeded`,
|
|
3238
3745
|
metadata: {
|
|
3239
3746
|
agentId,
|
|
3747
|
+
agentName: config.agentName,
|
|
3240
3748
|
toolCallsExecuted: 0,
|
|
3241
3749
|
executionTimeMs: Date.now() - startTime,
|
|
3242
3750
|
errorMessage: "Max delegation depth exceeded"
|
|
@@ -3300,6 +3808,16 @@ var AgentManager = class {
|
|
|
3300
3808
|
// Specialists run autonomously
|
|
3301
3809
|
reasoningEffort: freshConfig.reasoningEffort ?? this.delegatingConfig.reasoningEffort
|
|
3302
3810
|
};
|
|
3811
|
+
const metricsPort = new InMemoryMetricsPort((snapshot) => {
|
|
3812
|
+
this.eventCallback?.({
|
|
3813
|
+
type: AgentEventTypes.SubAgentMetrics,
|
|
3814
|
+
conversationId: config.conversationId ?? "default",
|
|
3815
|
+
messageId: config.messageId ?? "",
|
|
3816
|
+
agentId: config.agentId,
|
|
3817
|
+
toolCallId: config.toolCallId ?? "",
|
|
3818
|
+
metrics: snapshot
|
|
3819
|
+
});
|
|
3820
|
+
});
|
|
3303
3821
|
const llm = this.resolveLLM(config);
|
|
3304
3822
|
const specialistOrchestrator = new AgentOrchestrator(specialistConfig, {
|
|
3305
3823
|
memory,
|
|
@@ -3310,7 +3828,8 @@ var AgentManager = class {
|
|
|
3310
3828
|
clock: new SystemClock(),
|
|
3311
3829
|
cost: new SimpleCost(),
|
|
3312
3830
|
reminders: new NoopReminders(),
|
|
3313
|
-
events: eventPort
|
|
3831
|
+
events: eventPort,
|
|
3832
|
+
metrics: metricsPort
|
|
3314
3833
|
});
|
|
3315
3834
|
this.activeAgents.set(agentId, specialistOrchestrator);
|
|
3316
3835
|
try {
|
|
@@ -3325,6 +3844,7 @@ var AgentManager = class {
|
|
|
3325
3844
|
totalTokens += event.usage.total_tokens;
|
|
3326
3845
|
}
|
|
3327
3846
|
}
|
|
3847
|
+
const snapshot = metricsPort.getSnapshot();
|
|
3328
3848
|
this.eventCallback?.({
|
|
3329
3849
|
type: AgentEventTypes.SubAgentCompleted,
|
|
3330
3850
|
conversationId: config.conversationId ?? "default",
|
|
@@ -3340,11 +3860,13 @@ var AgentManager = class {
|
|
|
3340
3860
|
result: response.content || "",
|
|
3341
3861
|
metadata: {
|
|
3342
3862
|
agentId,
|
|
3863
|
+
agentName: config.agentName,
|
|
3343
3864
|
tokensUsed: totalTokens || response.metadata?.totalTokens,
|
|
3344
3865
|
toolCallsExecuted,
|
|
3345
3866
|
executionTimeMs,
|
|
3346
3867
|
conversationHistory,
|
|
3347
|
-
events
|
|
3868
|
+
events,
|
|
3869
|
+
metrics: snapshot
|
|
3348
3870
|
}
|
|
3349
3871
|
};
|
|
3350
3872
|
} catch (error) {
|
|
@@ -3368,6 +3890,7 @@ var AgentManager = class {
|
|
|
3368
3890
|
result: errorMessage,
|
|
3369
3891
|
metadata: {
|
|
3370
3892
|
agentId,
|
|
3893
|
+
agentName: config.agentName,
|
|
3371
3894
|
toolCallsExecuted: events.filter((e) => e.type === "tool_calls").length,
|
|
3372
3895
|
executionTimeMs,
|
|
3373
3896
|
errorMessage,
|
|
@@ -3541,10 +4064,12 @@ var DefaultDelegationResultFormatter = class {
|
|
|
3541
4064
|
summary: result.result,
|
|
3542
4065
|
metadata: {
|
|
3543
4066
|
agentId,
|
|
4067
|
+
agentName: result.metadata.agentName,
|
|
3544
4068
|
status: result.status,
|
|
3545
4069
|
executionTimeMs: result.metadata.executionTimeMs,
|
|
3546
4070
|
toolCallsExecuted: result.metadata.toolCallsExecuted,
|
|
3547
|
-
tokensUsed: result.metadata.tokensUsed
|
|
4071
|
+
tokensUsed: result.metadata.tokensUsed,
|
|
4072
|
+
metrics: result.metadata.metrics
|
|
3548
4073
|
}
|
|
3549
4074
|
};
|
|
3550
4075
|
}
|
|
@@ -3803,6 +4328,121 @@ var CompositeToolPort = class {
|
|
|
3803
4328
|
}
|
|
3804
4329
|
};
|
|
3805
4330
|
|
|
4331
|
+
// src/tools/tool-params.ts
|
|
4332
|
+
function parseToolArguments(args) {
|
|
4333
|
+
if (typeof args === "string") {
|
|
4334
|
+
try {
|
|
4335
|
+
return JSON.parse(args);
|
|
4336
|
+
} catch {
|
|
4337
|
+
return {};
|
|
4338
|
+
}
|
|
4339
|
+
}
|
|
4340
|
+
return args;
|
|
4341
|
+
}
|
|
4342
|
+
function isBashToolArgs(args) {
|
|
4343
|
+
return "cmd" in args && typeof args.cmd === "string";
|
|
4344
|
+
}
|
|
4345
|
+
function isFileReadArgs(args) {
|
|
4346
|
+
return "path" in args && typeof args.path === "string";
|
|
4347
|
+
}
|
|
4348
|
+
function isFileEditArgs(args) {
|
|
4349
|
+
return "file_path" in args && "old_text" in args && "new_text" in args;
|
|
4350
|
+
}
|
|
4351
|
+
function isFileNewArgs(args) {
|
|
4352
|
+
return "file_path" in args && "content" in args;
|
|
4353
|
+
}
|
|
4354
|
+
function isTodoWriteArgs(args) {
|
|
4355
|
+
return "todos" in args && Array.isArray(args.todos);
|
|
4356
|
+
}
|
|
4357
|
+
function isAssignTaskArgs(args) {
|
|
4358
|
+
return "agent" in args && "task" in args && "description" in args;
|
|
4359
|
+
}
|
|
4360
|
+
function isWebSearchArgs(args) {
|
|
4361
|
+
return "query" in args && typeof args.query === "string";
|
|
4362
|
+
}
|
|
4363
|
+
function isWebFetchArgs(args) {
|
|
4364
|
+
return "url" in args && typeof args.url === "string";
|
|
4365
|
+
}
|
|
4366
|
+
function isDirLsArgs(args) {
|
|
4367
|
+
return !("cmd" in args) && !("url" in args) && !("query" in args) && !("todos" in args) && !("agent" in args) && !("file_path" in args) && !("content" in args);
|
|
4368
|
+
}
|
|
4369
|
+
|
|
4370
|
+
// src/tools/type-guards.ts
|
|
4371
|
+
function isSuccess(result) {
|
|
4372
|
+
return result.status === "success";
|
|
4373
|
+
}
|
|
4374
|
+
function isError(result) {
|
|
4375
|
+
return result.status === "error";
|
|
4376
|
+
}
|
|
4377
|
+
function isTextResult(result) {
|
|
4378
|
+
return result.type === "text";
|
|
4379
|
+
}
|
|
4380
|
+
function isJsonResult(result) {
|
|
4381
|
+
return result.type === "json";
|
|
4382
|
+
}
|
|
4383
|
+
function isSuccessText(result) {
|
|
4384
|
+
return result.status === "success" && result.type === "text";
|
|
4385
|
+
}
|
|
4386
|
+
function isSuccessJson(result) {
|
|
4387
|
+
return result.status === "success" && result.type === "json";
|
|
4388
|
+
}
|
|
4389
|
+
|
|
4390
|
+
// src/tools/tool-type-guards.ts
|
|
4391
|
+
function isBashResult(result) {
|
|
4392
|
+
return result.name === "bash_tool";
|
|
4393
|
+
}
|
|
4394
|
+
function isBashSuccess(result) {
|
|
4395
|
+
return result.name === "bash_tool" && result.status === "success" && result.type === "text";
|
|
4396
|
+
}
|
|
4397
|
+
function isFileReadResult(result) {
|
|
4398
|
+
return result.name === "file_read";
|
|
4399
|
+
}
|
|
4400
|
+
function isFileReadSuccess(result) {
|
|
4401
|
+
return result.name === "file_read" && result.status === "success" && result.type === "text";
|
|
4402
|
+
}
|
|
4403
|
+
function isFileEditResult(result) {
|
|
4404
|
+
return result.name === "file_edit";
|
|
4405
|
+
}
|
|
4406
|
+
function isFileEditSuccess(result) {
|
|
4407
|
+
return result.name === "file_edit" && result.status === "success" && result.type === "text";
|
|
4408
|
+
}
|
|
4409
|
+
function isFileNewResult(result) {
|
|
4410
|
+
return result.name === "file_new";
|
|
4411
|
+
}
|
|
4412
|
+
function isFileNewSuccess(result) {
|
|
4413
|
+
return result.name === "file_new" && result.status === "success" && result.type === "text";
|
|
4414
|
+
}
|
|
4415
|
+
function isDirLsResult(result) {
|
|
4416
|
+
return result.name === "dir_ls";
|
|
4417
|
+
}
|
|
4418
|
+
function isDirLsSuccess(result) {
|
|
4419
|
+
return result.name === "dir_ls" && result.status === "success" && result.type === "json";
|
|
4420
|
+
}
|
|
4421
|
+
function isWebSearchResult(result) {
|
|
4422
|
+
return result.name === "web_search";
|
|
4423
|
+
}
|
|
4424
|
+
function isWebSearchSuccess(result) {
|
|
4425
|
+
return result.name === "web_search" && result.status === "success" && result.type === "json";
|
|
4426
|
+
}
|
|
4427
|
+
function isWebFetchResult(result) {
|
|
4428
|
+
return result.name === "web_fetch";
|
|
4429
|
+
}
|
|
4430
|
+
function isWebFetchSuccess(result) {
|
|
4431
|
+
return result.name === "web_fetch" && result.status === "success" && result.type === "text";
|
|
4432
|
+
}
|
|
4433
|
+
function isTodoWriteResult(result) {
|
|
4434
|
+
return result.name === "todo_write";
|
|
4435
|
+
}
|
|
4436
|
+
function isTodoWriteSuccess(result) {
|
|
4437
|
+
return result.name === "todo_write" && result.status === "success" && result.type === "text";
|
|
4438
|
+
}
|
|
4439
|
+
function isAssignResult(result) {
|
|
4440
|
+
return result.name === "assign_task";
|
|
4441
|
+
}
|
|
4442
|
+
function isAssignSuccess(result) {
|
|
4443
|
+
return result.name === "assign_task" && result.status === "success" && result.type === "text";
|
|
4444
|
+
}
|
|
4445
|
+
|
|
3806
4446
|
// src/agent-file-persistence.ts
|
|
3807
4447
|
import * as fs8 from "fs";
|
|
3808
4448
|
import * as path7 from "path";
|
|
@@ -3927,6 +4567,16 @@ var AgentFilePersistence = class {
|
|
|
3927
4567
|
}
|
|
3928
4568
|
};
|
|
3929
4569
|
|
|
4570
|
+
// src/sub-agent-types.ts
|
|
4571
|
+
function parseSubAgentToolCallArguments(argsString) {
|
|
4572
|
+
if (!argsString) return {};
|
|
4573
|
+
try {
|
|
4574
|
+
return JSON.parse(argsString);
|
|
4575
|
+
} catch {
|
|
4576
|
+
return {};
|
|
4577
|
+
}
|
|
4578
|
+
}
|
|
4579
|
+
|
|
3930
4580
|
// src/llm-providers/llm-utils.ts
|
|
3931
4581
|
function mergeChoices(choices) {
|
|
3932
4582
|
const contentParts = [];
|
|
@@ -5731,7 +6381,11 @@ var MCPToolPort = class {
|
|
|
5731
6381
|
try {
|
|
5732
6382
|
const res = await this.client.callTool({ name: original, arguments: c.parameters || {} });
|
|
5733
6383
|
const flat = flattenMcpContent(res.content);
|
|
5734
|
-
|
|
6384
|
+
if (flat.type === "text") {
|
|
6385
|
+
return { id: c.id, name: c.name, status: "success", type: "text", result: flat.value };
|
|
6386
|
+
} else {
|
|
6387
|
+
return { id: c.id, name: c.name, status: "success", type: "json", result: flat.value };
|
|
6388
|
+
}
|
|
5735
6389
|
} catch (err2) {
|
|
5736
6390
|
const message = err2 instanceof Error ? err2.message : String(err2);
|
|
5737
6391
|
return { id: c.id, name: c.name, status: "error", type: "text", result: message };
|
|
@@ -5850,19 +6504,61 @@ export {
|
|
|
5850
6504
|
buildAgentCreationPrompt,
|
|
5851
6505
|
buildInjectedSystem,
|
|
5852
6506
|
canonicalizeTerminalPaste,
|
|
6507
|
+
convertToolCall,
|
|
6508
|
+
convertToolCalls,
|
|
5853
6509
|
createEmptySnapshot,
|
|
5854
6510
|
createLLM,
|
|
6511
|
+
err,
|
|
5855
6512
|
generateFolderTree,
|
|
5856
6513
|
getAvailableProviders,
|
|
5857
6514
|
getFallbackLimits,
|
|
5858
6515
|
getProviderLabel,
|
|
6516
|
+
isAssignResult,
|
|
6517
|
+
isAssignSuccess,
|
|
6518
|
+
isAssignTaskArgs,
|
|
6519
|
+
isBashResult,
|
|
6520
|
+
isBashSuccess,
|
|
6521
|
+
isBashToolArgs,
|
|
6522
|
+
isDirLsArgs,
|
|
6523
|
+
isDirLsResult,
|
|
6524
|
+
isDirLsSuccess,
|
|
6525
|
+
isError,
|
|
6526
|
+
isFileEditArgs,
|
|
6527
|
+
isFileEditResult,
|
|
6528
|
+
isFileEditSuccess,
|
|
6529
|
+
isFileNewArgs,
|
|
6530
|
+
isFileNewResult,
|
|
6531
|
+
isFileNewSuccess,
|
|
6532
|
+
isFileReadArgs,
|
|
6533
|
+
isFileReadResult,
|
|
6534
|
+
isFileReadSuccess,
|
|
6535
|
+
isJsonResult,
|
|
6536
|
+
isSuccess,
|
|
6537
|
+
isSuccessJson,
|
|
6538
|
+
isSuccessText,
|
|
6539
|
+
isTextResult,
|
|
6540
|
+
isTodoWriteArgs,
|
|
6541
|
+
isTodoWriteResult,
|
|
6542
|
+
isTodoWriteSuccess,
|
|
6543
|
+
isWebFetchArgs,
|
|
6544
|
+
isWebFetchResult,
|
|
6545
|
+
isWebFetchSuccess,
|
|
6546
|
+
isWebSearchArgs,
|
|
6547
|
+
isWebSearchResult,
|
|
6548
|
+
isWebSearchSuccess,
|
|
5859
6549
|
loadMCPConfig,
|
|
5860
6550
|
normalizeModelInfo,
|
|
5861
6551
|
normalizeModelLimits,
|
|
5862
6552
|
normalizeNewlines,
|
|
6553
|
+
okJson,
|
|
6554
|
+
okText,
|
|
6555
|
+
parseJSON,
|
|
6556
|
+
parseSubAgentToolCallArguments,
|
|
6557
|
+
parseToolArguments,
|
|
5863
6558
|
renderTemplate,
|
|
5864
6559
|
resolveBackspaces,
|
|
5865
6560
|
resolveCarriageReturns,
|
|
5866
6561
|
stripAnsiAndControls,
|
|
5867
|
-
supportsGetModels
|
|
6562
|
+
supportsGetModels,
|
|
6563
|
+
toolValidators
|
|
5868
6564
|
};
|