@clinebot/core 0.0.36 → 0.0.37
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/ClineCore.d.ts +312 -3
- package/dist/ClineCore.d.ts.map +1 -1
- package/dist/account/cline-account-service.d.ts.map +1 -1
- package/dist/cron/cron-event-ingress.d.ts +38 -0
- package/dist/cron/cron-event-ingress.d.ts.map +1 -0
- package/dist/cron/cron-materializer.d.ts +36 -0
- package/dist/cron/cron-materializer.d.ts.map +1 -0
- package/dist/cron/cron-reconciler.d.ts +62 -0
- package/dist/cron/cron-reconciler.d.ts.map +1 -0
- package/dist/cron/cron-report-writer.d.ts +41 -0
- package/dist/cron/cron-report-writer.d.ts.map +1 -0
- package/dist/cron/cron-runner.d.ts +43 -0
- package/dist/cron/cron-runner.d.ts.map +1 -0
- package/dist/cron/cron-schema.d.ts +3 -0
- package/dist/cron/cron-schema.d.ts.map +1 -0
- package/dist/cron/cron-service.d.ts +57 -0
- package/dist/cron/cron-service.d.ts.map +1 -0
- package/dist/cron/cron-spec-parser.d.ts +27 -0
- package/dist/cron/cron-spec-parser.d.ts.map +1 -0
- package/dist/cron/cron-watcher.d.ts +23 -0
- package/dist/cron/cron-watcher.d.ts.map +1 -0
- package/dist/cron/scheduler.d.ts +3 -1
- package/dist/cron/scheduler.d.ts.map +1 -1
- package/dist/cron/sqlite-cron-store.d.ts +230 -0
- package/dist/cron/sqlite-cron-store.d.ts.map +1 -0
- package/dist/extensions/plugin/plugin-config-loader.d.ts +7 -1
- package/dist/extensions/plugin/plugin-config-loader.d.ts.map +1 -1
- package/dist/extensions/plugin/plugin-loader.d.ts +10 -6
- package/dist/extensions/plugin/plugin-loader.d.ts.map +1 -1
- package/dist/extensions/plugin/plugin-sandbox.d.ts +7 -1
- package/dist/extensions/plugin/plugin-sandbox.d.ts.map +1 -1
- package/dist/extensions/plugin-sandbox-bootstrap.js +236 -275
- package/dist/extensions/tools/constants.d.ts +1 -0
- package/dist/extensions/tools/constants.d.ts.map +1 -1
- package/dist/extensions/tools/definitions.d.ts +2 -3
- package/dist/extensions/tools/definitions.d.ts.map +1 -1
- package/dist/extensions/tools/executors/editor.d.ts.map +1 -1
- package/dist/extensions/tools/helpers.d.ts +1 -0
- package/dist/extensions/tools/helpers.d.ts.map +1 -1
- package/dist/extensions/tools/index.d.ts +1 -2
- package/dist/extensions/tools/index.d.ts.map +1 -1
- package/dist/extensions/tools/presets.d.ts +1 -1
- package/dist/extensions/tools/schemas.d.ts +25 -3
- package/dist/extensions/tools/schemas.d.ts.map +1 -1
- package/dist/extensions/tools/team/delegated-agent.d.ts +2 -2
- package/dist/extensions/tools/team/delegated-agent.d.ts.map +1 -1
- package/dist/extensions/tools/team/multi-agent.d.ts +7 -3
- package/dist/extensions/tools/team/multi-agent.d.ts.map +1 -1
- package/dist/extensions/tools/team/team-tools.d.ts.map +1 -1
- package/dist/extensions/tools/types.d.ts +0 -5
- package/dist/extensions/tools/types.d.ts.map +1 -1
- package/dist/hooks/hook-bridge.d.ts +118 -0
- package/dist/hooks/hook-bridge.d.ts.map +1 -0
- package/dist/hooks/hook-file-hooks.d.ts +2 -1
- package/dist/hooks/hook-file-hooks.d.ts.map +1 -1
- package/dist/hooks/hook-registry.d.ts +16 -0
- package/dist/hooks/hook-registry.d.ts.map +1 -0
- package/dist/hub/browser-websocket.d.ts.map +1 -1
- package/dist/hub/client.d.ts +7 -1
- package/dist/hub/client.d.ts.map +1 -1
- package/dist/hub/daemon-entry.js +721 -461
- package/dist/hub/daemon.d.ts.map +1 -1
- package/dist/hub/defaults.d.ts +8 -4
- package/dist/hub/defaults.d.ts.map +1 -1
- package/dist/hub/index.js +665 -415
- package/dist/hub/runtime-handlers.d.ts.map +1 -1
- package/dist/hub/server.d.ts +18 -0
- package/dist/hub/server.d.ts.map +1 -1
- package/dist/hub/session-client.d.ts +3 -0
- package/dist/hub/session-client.d.ts.map +1 -1
- package/dist/hub/start-shared-server.d.ts.map +1 -1
- package/dist/hub/ui-client.d.ts +1 -0
- package/dist/hub/ui-client.d.ts.map +1 -1
- package/dist/index.d.ts +9 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +756 -467
- package/dist/llms/cline-recommended-models.d.ts +20 -0
- package/dist/llms/cline-recommended-models.d.ts.map +1 -0
- package/dist/llms/handler-factory.d.ts +16 -0
- package/dist/llms/handler-factory.d.ts.map +1 -0
- package/dist/llms/provider-defaults.d.ts.map +1 -1
- package/dist/llms/provider-settings.d.ts +45 -2
- package/dist/llms/provider-settings.d.ts.map +1 -1
- package/dist/llms/runtime-registry.d.ts.map +1 -1
- package/dist/runtime/agent-config-adapter.d.ts +148 -0
- package/dist/runtime/agent-config-adapter.d.ts.map +1 -0
- package/dist/runtime/agent-runtime-config-builder.d.ts +96 -0
- package/dist/runtime/agent-runtime-config-builder.d.ts.map +1 -0
- package/dist/runtime/history.d.ts +6 -0
- package/dist/runtime/history.d.ts.map +1 -1
- package/dist/runtime/host.d.ts.map +1 -1
- package/dist/runtime/loop-detection.d.ts +59 -0
- package/dist/runtime/loop-detection.d.ts.map +1 -0
- package/dist/runtime/mistake-tracker.d.ts +69 -0
- package/dist/runtime/mistake-tracker.d.ts.map +1 -0
- package/dist/runtime/runtime-builder.d.ts.map +1 -1
- package/dist/runtime/runtime-event-adapter.d.ts +102 -0
- package/dist/runtime/runtime-event-adapter.d.ts.map +1 -0
- package/dist/runtime/runtime-host.d.ts +28 -3
- package/dist/runtime/runtime-host.d.ts.map +1 -1
- package/dist/runtime/session-runtime-orchestrator.d.ts +261 -0
- package/dist/runtime/session-runtime-orchestrator.d.ts.map +1 -0
- package/dist/runtime/session-runtime.d.ts +16 -3
- package/dist/runtime/session-runtime.d.ts.map +1 -1
- package/dist/runtime/user-input-builder.d.ts +24 -0
- package/dist/runtime/user-input-builder.d.ts.map +1 -0
- package/dist/services/index.js +28 -0
- package/dist/services/local-runtime-bootstrap.d.ts.map +1 -1
- package/dist/services/plugin-tools.d.ts.map +1 -1
- package/dist/services/providers/local-provider-registry.d.ts +197 -21
- package/dist/services/providers/local-provider-registry.d.ts.map +1 -1
- package/dist/services/providers/local-provider-service.d.ts +3 -1
- package/dist/services/providers/local-provider-service.d.ts.map +1 -1
- package/dist/services/session-data.d.ts.map +1 -1
- package/dist/services/session-telemetry.d.ts +7 -2
- package/dist/services/session-telemetry.d.ts.map +1 -1
- package/dist/services/storage/file-team-store.d.ts.map +1 -1
- package/dist/services/storage/provider-settings-legacy-migration.d.ts.map +1 -1
- package/dist/services/storage/provider-settings-manager.d.ts +1 -0
- package/dist/services/storage/provider-settings-manager.d.ts.map +1 -1
- package/dist/services/storage/sqlite-team-store.d.ts.map +1 -1
- package/dist/session/conversation-store.d.ts +30 -0
- package/dist/session/conversation-store.d.ts.map +1 -0
- package/dist/session/message-builder.d.ts +65 -0
- package/dist/session/message-builder.d.ts.map +1 -0
- package/dist/session/session-manifest.d.ts +1 -1
- package/dist/transports/hub.d.ts +14 -3
- package/dist/transports/hub.d.ts.map +1 -1
- package/dist/transports/local.d.ts +14 -4
- package/dist/transports/local.d.ts.map +1 -1
- package/dist/transports/remote.d.ts.map +1 -1
- package/dist/types/chat-schema.d.ts +5 -5
- package/dist/types/config.d.ts +9 -0
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/events.d.ts +7 -6
- package/dist/types/events.d.ts.map +1 -1
- package/dist/types/provider-settings.d.ts +2 -2
- package/dist/types/provider-settings.d.ts.map +1 -1
- package/dist/types/session.d.ts +5 -2
- package/dist/types/session.d.ts.map +1 -1
- package/dist/types.d.ts +4 -4
- package/dist/types.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/ClineCore.ts +691 -6
- package/src/account/cline-account-service.ts +44 -6
- package/src/cron/cron-event-ingress.ts +357 -0
- package/src/cron/cron-materializer.ts +97 -0
- package/src/cron/cron-reconciler.ts +241 -0
- package/src/cron/cron-report-writer.ts +153 -0
- package/src/cron/cron-runner.ts +495 -0
- package/src/cron/cron-schema.ts +127 -0
- package/src/cron/cron-service.ts +163 -0
- package/src/cron/cron-spec-parser.ts +489 -0
- package/src/cron/cron-watcher.ts +102 -0
- package/src/cron/index.ts +10 -0
- package/src/cron/scheduler.ts +141 -6
- package/src/cron/sqlite-cron-store.ts +1286 -0
- package/src/extensions/plugin/plugin-config-loader.ts +21 -1
- package/src/extensions/plugin/plugin-loader.ts +25 -9
- package/src/extensions/plugin/plugin-sandbox-bootstrap.ts +151 -1
- package/src/extensions/plugin/plugin-sandbox.ts +131 -7
- package/src/extensions/tools/constants.ts +2 -0
- package/src/extensions/tools/definitions.ts +31 -22
- package/src/extensions/tools/executors/editor.ts +4 -3
- package/src/extensions/tools/helpers.ts +24 -0
- package/src/extensions/tools/index.ts +1 -2
- package/src/extensions/tools/presets.ts +1 -1
- package/src/extensions/tools/schemas.ts +13 -18
- package/src/extensions/tools/team/delegated-agent.ts +8 -3
- package/src/extensions/tools/team/multi-agent.ts +135 -19
- package/src/extensions/tools/team/team-tools.ts +151 -91
- package/src/extensions/tools/types.ts +0 -6
- package/src/hooks/hook-bridge.ts +489 -0
- package/src/hooks/hook-file-hooks.ts +58 -3
- package/src/hooks/hook-registry.ts +257 -0
- package/src/hub/browser-websocket.ts +26 -4
- package/src/hub/client.ts +72 -13
- package/src/hub/daemon-entry.ts +35 -0
- package/src/hub/daemon.ts +117 -14
- package/src/hub/defaults.ts +39 -12
- package/src/hub/runtime-handlers.ts +4 -3
- package/src/hub/server.ts +506 -77
- package/src/hub/session-client.ts +43 -1
- package/src/hub/start-shared-server.ts +3 -0
- package/src/hub/ui-client.ts +4 -0
- package/src/index.ts +46 -1
- package/src/llms/cline-recommended-models.ts +167 -0
- package/src/llms/handler-factory.ts +56 -0
- package/src/llms/provider-defaults.ts +17 -1
- package/src/llms/provider-settings.ts +48 -1
- package/src/llms/runtime-registry.ts +1 -0
- package/src/runtime/agent-config-adapter.ts +636 -0
- package/src/runtime/agent-runtime-config-builder.ts +205 -0
- package/src/runtime/error-feedback.ts +142 -0
- package/src/runtime/history.ts +137 -0
- package/src/runtime/host.ts +22 -0
- package/src/runtime/loop-detection.ts +162 -0
- package/src/runtime/mistake-tracker.ts +221 -0
- package/src/runtime/runtime-builder.ts +61 -5
- package/src/runtime/runtime-event-adapter.ts +412 -0
- package/src/runtime/runtime-host.ts +45 -1
- package/src/runtime/session-runtime-orchestrator.ts +1253 -0
- package/src/runtime/session-runtime.ts +16 -2
- package/src/runtime/user-input-builder.ts +167 -0
- package/src/services/local-runtime-bootstrap.ts +128 -22
- package/src/services/plugin-tools.ts +1 -0
- package/src/services/providers/local-provider-registry.ts +273 -57
- package/src/services/providers/local-provider-service.ts +67 -7
- package/src/services/session-data.ts +16 -14
- package/src/services/session-telemetry.ts +6 -15
- package/src/services/storage/file-team-store.ts +1 -5
- package/src/services/storage/provider-settings-legacy-migration.ts +8 -47
- package/src/services/storage/provider-settings-manager.ts +16 -1
- package/src/services/storage/sqlite-team-store.ts +1 -5
- package/src/session/conversation-store.ts +77 -0
- package/src/session/message-builder.ts +941 -0
- package/src/transports/hub.ts +458 -33
- package/src/transports/local.ts +296 -65
- package/src/transports/remote.ts +1 -0
- package/src/types/config.ts +9 -0
- package/src/types/events.ts +8 -6
- package/src/types/index.ts +3 -0
- package/src/types/provider-settings.ts +8 -1
- package/src/types/session.ts +5 -2
- package/src/types.ts +15 -1
- package/dist/cron/index.d.ts +0 -6
- package/dist/cron/index.d.ts.map +0 -1
- package/dist/services/telemetry/index.js +0 -28
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
formatReadFileQuery,
|
|
16
16
|
formatRunCommandQuery,
|
|
17
17
|
getEditorSizeError,
|
|
18
|
+
getReadFileRangeError,
|
|
18
19
|
normalizeReadFileRequests,
|
|
19
20
|
normalizeRunCommandsInput,
|
|
20
21
|
withTimeout,
|
|
@@ -92,6 +93,16 @@ export function createReadFilesTool(
|
|
|
92
93
|
|
|
93
94
|
return Promise.all(
|
|
94
95
|
requests.map(async (request): Promise<ToolOperationResult> => {
|
|
96
|
+
const rangeError = getReadFileRangeError(request);
|
|
97
|
+
if (rangeError) {
|
|
98
|
+
return {
|
|
99
|
+
query: formatReadFileQuery(request),
|
|
100
|
+
result: "",
|
|
101
|
+
error: `Invalid file range: ${rangeError}`,
|
|
102
|
+
success: false,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
95
106
|
try {
|
|
96
107
|
const content = await withTimeout(
|
|
97
108
|
executor(request, context),
|
|
@@ -206,16 +217,23 @@ export function createBashTool(
|
|
|
206
217
|
maxRetries: 0,
|
|
207
218
|
execute: async (input, context) => {
|
|
208
219
|
const validate = validateWithZod(RunCommandsInputUnionSchema, input);
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
220
|
+
let commands: string[];
|
|
221
|
+
if (typeof validate === "string") {
|
|
222
|
+
commands = [validate];
|
|
223
|
+
} else if (Array.isArray(validate)) {
|
|
224
|
+
commands = validate;
|
|
225
|
+
} else if ("commands" in validate) {
|
|
226
|
+
commands = Array.isArray(validate.commands)
|
|
227
|
+
? validate.commands
|
|
228
|
+
: [validate.commands];
|
|
229
|
+
} else if ("command" in validate) {
|
|
230
|
+
commands = [validate.command];
|
|
231
|
+
} else {
|
|
232
|
+
commands = [validate.cmd];
|
|
233
|
+
}
|
|
216
234
|
|
|
217
235
|
return Promise.all(
|
|
218
|
-
commands.map(async (command): Promise<ToolOperationResult> => {
|
|
236
|
+
commands.map(async (command: string): Promise<ToolOperationResult> => {
|
|
219
237
|
try {
|
|
220
238
|
const output = await withTimeout(
|
|
221
239
|
executor(command, cwd, context),
|
|
@@ -564,11 +582,8 @@ export function createSkillsTool(
|
|
|
564
582
|
*/
|
|
565
583
|
export function createAskQuestionTool(
|
|
566
584
|
executor: AskQuestionExecutor,
|
|
567
|
-
config: Pick<DefaultToolsConfig, "askQuestionTimeoutMs"> = {},
|
|
568
585
|
): Tool<AskQuestionInput, string> {
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
return createTool<AskQuestionInput, string>({
|
|
586
|
+
return {
|
|
572
587
|
name: "ask_question",
|
|
573
588
|
description:
|
|
574
589
|
"Ask user a question for clarifying or gathering information needed to complete the task. " +
|
|
@@ -577,18 +592,13 @@ export function createAskQuestionTool(
|
|
|
577
592
|
"Provide an array of 2-5 options for the user to choose from. " +
|
|
578
593
|
"Never include an option to toggle to Act mode.",
|
|
579
594
|
inputSchema: zodToJsonSchema(AskQuestionInputSchema),
|
|
580
|
-
timeoutMs,
|
|
581
595
|
retryable: false,
|
|
582
596
|
maxRetries: 0,
|
|
583
597
|
execute: async (input, context) => {
|
|
584
598
|
const validatedInput = validateWithZod(AskQuestionInputSchema, input);
|
|
585
|
-
return
|
|
586
|
-
executor(validatedInput.question, validatedInput.options, context),
|
|
587
|
-
timeoutMs,
|
|
588
|
-
`ask_question timed out after ${timeoutMs}ms`,
|
|
589
|
-
);
|
|
599
|
+
return executor(validatedInput.question, validatedInput.options, context);
|
|
590
600
|
},
|
|
591
|
-
}
|
|
601
|
+
};
|
|
592
602
|
}
|
|
593
603
|
|
|
594
604
|
export function createSubmitAndExitTool(
|
|
@@ -632,8 +642,7 @@ export function createSubmitAndExitTool(
|
|
|
632
642
|
*
|
|
633
643
|
* @example
|
|
634
644
|
* ```typescript
|
|
635
|
-
* import { Agent } from "@clinebot/
|
|
636
|
-
* import { createDefaultTools } from "@clinebot/core"
|
|
645
|
+
* import { Agent, createDefaultTools } from "@clinebot/core"
|
|
637
646
|
* import * as fs from "fs/promises"
|
|
638
647
|
* import { exec } from "child_process"
|
|
639
648
|
*
|
|
@@ -719,7 +728,7 @@ export function createDefaultTools(options: CreateDefaultToolsOptions): Tool[] {
|
|
|
719
728
|
|
|
720
729
|
// Add ask_question tool if enabled and executor provided
|
|
721
730
|
if (enableAskQuestion && executors.askQuestion) {
|
|
722
|
-
tools.push(createAskQuestionTool(executors.askQuestion
|
|
731
|
+
tools.push(createAskQuestionTool(executors.askQuestion));
|
|
723
732
|
} else if (enableSubmitAndExit && executors.submit) {
|
|
724
733
|
// Add submit_and_exit tool if enabled and executor provided
|
|
725
734
|
tools.push(createSubmitAndExitTool(executors.submit, config));
|
|
@@ -157,14 +157,15 @@ async function insertInFile(
|
|
|
157
157
|
): Promise<string> {
|
|
158
158
|
const content = await fs.readFile(filePath, encoding);
|
|
159
159
|
const lines = content.split("\n");
|
|
160
|
-
const
|
|
160
|
+
const maxBoundaryLine = lines.length + 1;
|
|
161
161
|
|
|
162
|
-
if (
|
|
162
|
+
if (insertLineOneBased < 1 || insertLineOneBased > maxBoundaryLine) {
|
|
163
163
|
throw new Error(
|
|
164
|
-
`Invalid
|
|
164
|
+
`Invalid insert_line: ${insertLineOneBased}. insert_line must be a positive one-based boundary line in the range 1-${maxBoundaryLine}. Use ${maxBoundaryLine} to append at EOF.`,
|
|
165
165
|
);
|
|
166
166
|
}
|
|
167
167
|
|
|
168
|
+
const insertLine = insertLineOneBased - 1;
|
|
168
169
|
lines.splice(insertLine, 0, ...newStr.split("\n"));
|
|
169
170
|
await fs.writeFile(filePath, lines.join("\n"), { encoding });
|
|
170
171
|
|
|
@@ -76,6 +76,13 @@ export function normalizeReadFileRequests(input: unknown): ReadFileRequest[] {
|
|
|
76
76
|
return filePaths.map((filePath) => ({ path: filePath }));
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
+
if ("paths" in validate) {
|
|
80
|
+
const paths = Array.isArray(validate.paths)
|
|
81
|
+
? validate.paths
|
|
82
|
+
: [validate.paths];
|
|
83
|
+
return paths.map((path) => (typeof path === "string" ? { path } : path));
|
|
84
|
+
}
|
|
85
|
+
|
|
79
86
|
return [validate];
|
|
80
87
|
}
|
|
81
88
|
|
|
@@ -89,6 +96,15 @@ export function formatReadFileQuery(request: ReadFileRequest): string {
|
|
|
89
96
|
return `${path}:${start}-${end}`;
|
|
90
97
|
}
|
|
91
98
|
|
|
99
|
+
export function getReadFileRangeError(request: ReadFileRequest): string | null {
|
|
100
|
+
const { start_line, end_line } = request;
|
|
101
|
+
if (start_line == null || end_line == null || start_line <= end_line) {
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return `start_line must be less than or equal to end_line (received start_line: ${start_line}, end_line: ${end_line})`;
|
|
106
|
+
}
|
|
107
|
+
|
|
92
108
|
export function normalizeRunCommandsInput(
|
|
93
109
|
input: unknown,
|
|
94
110
|
): Array<string | StructuredCommandInput> {
|
|
@@ -108,6 +124,14 @@ export function normalizeRunCommandsInput(
|
|
|
108
124
|
: [validate.commands];
|
|
109
125
|
}
|
|
110
126
|
|
|
127
|
+
if ("command" in validate) {
|
|
128
|
+
return "args" in validate ? [validate] : [validate.command];
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if ("cmd" in validate) {
|
|
132
|
+
return [validate.cmd];
|
|
133
|
+
}
|
|
134
|
+
|
|
111
135
|
return [validate];
|
|
112
136
|
}
|
|
113
137
|
|
|
@@ -143,8 +143,7 @@ export interface CreateBuiltinToolsOptions
|
|
|
143
143
|
*
|
|
144
144
|
* @example
|
|
145
145
|
* ```typescript
|
|
146
|
-
* import { Agent } from "@clinebot/
|
|
147
|
-
* import { createBuiltinTools } from "@clinebot/core"
|
|
146
|
+
* import { Agent, createBuiltinTools } from "@clinebot/core"
|
|
148
147
|
*
|
|
149
148
|
* const tools = createBuiltinTools({
|
|
150
149
|
* cwd: "/path/to/project",
|
|
@@ -37,14 +37,7 @@ export const ReadFileLineRangeSchema = z
|
|
|
37
37
|
"Optional one-based ending line number to read through; use null or omit for the end of the file",
|
|
38
38
|
),
|
|
39
39
|
})
|
|
40
|
-
.
|
|
41
|
-
({ start_line, end_line }) =>
|
|
42
|
-
start_line == null || end_line == null || start_line <= end_line,
|
|
43
|
-
{
|
|
44
|
-
message: "start_line must be less than or equal to end_line",
|
|
45
|
-
path: ["end_line"],
|
|
46
|
-
},
|
|
47
|
-
);
|
|
40
|
+
.describe("Optional inclusive one-based file line range");
|
|
48
41
|
|
|
49
42
|
export const ReadFileRequestSchema = z
|
|
50
43
|
.object({
|
|
@@ -52,13 +45,8 @@ export const ReadFileRequestSchema = z
|
|
|
52
45
|
start_line: ReadFileLineRangeSchema.shape.start_line,
|
|
53
46
|
end_line: ReadFileLineRangeSchema.shape.end_line,
|
|
54
47
|
})
|
|
55
|
-
.
|
|
56
|
-
|
|
57
|
-
start_line == null || end_line == null || start_line <= end_line,
|
|
58
|
-
{
|
|
59
|
-
message: "start_line must be less than or equal to end_line",
|
|
60
|
-
path: ["end_line"],
|
|
61
|
-
},
|
|
48
|
+
.describe(
|
|
49
|
+
"A file read request with optional inclusive one-based line bounds",
|
|
62
50
|
);
|
|
63
51
|
|
|
64
52
|
/**
|
|
@@ -84,6 +72,9 @@ export const ReadFilesInputUnionSchema = z.union([
|
|
|
84
72
|
z.object({ files: ReadFileRequestSchema }),
|
|
85
73
|
z.object({ file_paths: z.array(AbsolutePath) }),
|
|
86
74
|
z.object({ file_paths: z.string() }),
|
|
75
|
+
z.object({ paths: z.array(z.union([AbsolutePath, ReadFileRequestSchema])) }),
|
|
76
|
+
z.object({ paths: ReadFileRequestSchema }),
|
|
77
|
+
z.object({ paths: z.string() }),
|
|
87
78
|
]);
|
|
88
79
|
|
|
89
80
|
/**
|
|
@@ -126,6 +117,8 @@ export const RunCommandsInputSchema = z.object({
|
|
|
126
117
|
export const RunCommandsInputUnionSchema = z.union([
|
|
127
118
|
RunCommandsInputSchema,
|
|
128
119
|
z.object({ commands: CommandInputSchema }),
|
|
120
|
+
z.object({ command: CommandInputSchema }),
|
|
121
|
+
z.object({ cmd: CommandInputSchema }),
|
|
129
122
|
z.array(z.string()),
|
|
130
123
|
z.string(),
|
|
131
124
|
]);
|
|
@@ -163,10 +156,12 @@ export const StructuredCommandsInputUnionSchema = z.union([
|
|
|
163
156
|
RunCommandsInputSchema,
|
|
164
157
|
StructuredCommandsInputSchema,
|
|
165
158
|
z.object({ commands: StructuredCommandEntrySchema }),
|
|
166
|
-
z.array(z.string()),
|
|
167
159
|
z.array(StructuredCommandInputSchema),
|
|
168
|
-
z.string(),
|
|
169
160
|
StructuredCommandInputSchema,
|
|
161
|
+
z.object({ command: CommandInputSchema }),
|
|
162
|
+
z.object({ cmd: CommandInputSchema }),
|
|
163
|
+
z.array(z.string()),
|
|
164
|
+
z.string(),
|
|
170
165
|
]);
|
|
171
166
|
|
|
172
167
|
/**
|
|
@@ -213,7 +208,7 @@ export const EditFileInputSchema = z
|
|
|
213
208
|
.nullable()
|
|
214
209
|
.optional()
|
|
215
210
|
.describe(
|
|
216
|
-
"Optional one-based line
|
|
211
|
+
"Optional positive one-based boundary line. When provided, the tool inserts new_text before that line instead of performing a replacement edit; use line_count + 1 to append at EOF.",
|
|
217
212
|
),
|
|
218
213
|
})
|
|
219
214
|
.describe(
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { Agent } from "@clinebot/agents";
|
|
2
1
|
import type {
|
|
3
2
|
AgentConfig,
|
|
4
3
|
AgentEvent,
|
|
@@ -10,6 +9,7 @@ import type {
|
|
|
10
9
|
ToolApprovalRequest,
|
|
11
10
|
ToolApprovalResult,
|
|
12
11
|
} from "@clinebot/shared";
|
|
12
|
+
import { SessionRuntime } from "../../../runtime/session-runtime-orchestrator";
|
|
13
13
|
import {
|
|
14
14
|
buildSubAgentSystemPrompt,
|
|
15
15
|
buildTeammateSystemPrompt,
|
|
@@ -126,6 +126,11 @@ export function buildDelegatedAgentConfig(
|
|
|
126
126
|
|
|
127
127
|
export function createDelegatedAgent(
|
|
128
128
|
options: BuildDelegatedAgentConfigOptions,
|
|
129
|
-
):
|
|
130
|
-
|
|
129
|
+
): SessionRuntime {
|
|
130
|
+
const config = buildDelegatedAgentConfig(options);
|
|
131
|
+
const session = new SessionRuntime(config);
|
|
132
|
+
if (config.onEvent) {
|
|
133
|
+
session.subscribeEvents(config.onEvent);
|
|
134
|
+
}
|
|
135
|
+
return session;
|
|
131
136
|
}
|
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
* Utilities for orchestrating multiple agents working together.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { type Agent, createAgent } from "@clinebot/agents";
|
|
8
7
|
import {
|
|
9
8
|
type AgentConfig,
|
|
10
9
|
type AgentEvent,
|
|
@@ -33,6 +32,7 @@ import {
|
|
|
33
32
|
type TeamTaskStatus,
|
|
34
33
|
} from "@clinebot/shared";
|
|
35
34
|
import { nanoid } from "nanoid";
|
|
35
|
+
import { SessionRuntime } from "../../../runtime/session-runtime-orchestrator";
|
|
36
36
|
|
|
37
37
|
// Re-export shared types for backward compatibility
|
|
38
38
|
export {
|
|
@@ -155,14 +155,26 @@ function isAbortLikeError(error: unknown): boolean {
|
|
|
155
155
|
);
|
|
156
156
|
}
|
|
157
157
|
|
|
158
|
+
function isIntentionalShutdownAbort(
|
|
159
|
+
member: TeamMemberState | undefined,
|
|
160
|
+
error: unknown,
|
|
161
|
+
): boolean {
|
|
162
|
+
return member?.status === "stopped" && isAbortLikeError(error);
|
|
163
|
+
}
|
|
164
|
+
|
|
158
165
|
// =============================================================================
|
|
159
166
|
// AgentTeam
|
|
160
167
|
// =============================================================================
|
|
161
168
|
|
|
162
169
|
const TEAMMATE_API_TIMEOUT_MS = 10 * 60 * 1000; // 10 minutes
|
|
170
|
+
const RECOVERED_QUEUED_ACTIVITY = "recovered_queued";
|
|
171
|
+
|
|
172
|
+
function buildRecoveredRunMessage(run: TeamRunRecord): string {
|
|
173
|
+
return `This is an automatic recovery of interrupted team run ${run.id}. The previous process stopped before completion. Continue the task safely, inspect the current workspace state before making changes, and avoid duplicating completed work.\n\n${run.message}`;
|
|
174
|
+
}
|
|
163
175
|
|
|
164
176
|
export class AgentTeam {
|
|
165
|
-
private agents: Map<string,
|
|
177
|
+
private agents: Map<string, SessionRuntime> = new Map();
|
|
166
178
|
private configs: Map<string, TeamMemberConfig> = new Map();
|
|
167
179
|
private onTeamEvent?: (event: TeamEvent) => void;
|
|
168
180
|
|
|
@@ -196,7 +208,10 @@ export class AgentTeam {
|
|
|
196
208
|
},
|
|
197
209
|
};
|
|
198
210
|
|
|
199
|
-
const agent =
|
|
211
|
+
const agent = new SessionRuntime(wrappedConfig);
|
|
212
|
+
if (wrappedConfig.onEvent) {
|
|
213
|
+
agent.subscribeEvents(wrappedConfig.onEvent);
|
|
214
|
+
}
|
|
200
215
|
this.agents.set(id, agent);
|
|
201
216
|
this.configs.set(id, config);
|
|
202
217
|
}
|
|
@@ -206,7 +221,7 @@ export class AgentTeam {
|
|
|
206
221
|
return this.agents.delete(id);
|
|
207
222
|
}
|
|
208
223
|
|
|
209
|
-
getAgent(id: string):
|
|
224
|
+
getAgent(id: string): SessionRuntime | undefined {
|
|
210
225
|
return this.agents.get(id);
|
|
211
226
|
}
|
|
212
227
|
|
|
@@ -497,7 +512,7 @@ export function createWorkerReviewerTeam(configs: {
|
|
|
497
512
|
// =============================================================================
|
|
498
513
|
|
|
499
514
|
interface TeamMemberState extends TeamMemberSnapshot {
|
|
500
|
-
agent?:
|
|
515
|
+
agent?: SessionRuntime;
|
|
501
516
|
runningCount: number;
|
|
502
517
|
lastMissionStep: number;
|
|
503
518
|
lastMissionAt: number;
|
|
@@ -522,6 +537,7 @@ export class AgentTeamsRuntime {
|
|
|
522
537
|
private readonly runs: Map<string, TeamRunRecord & { result?: AgentResult }> =
|
|
523
538
|
new Map();
|
|
524
539
|
private readonly runQueue: string[] = [];
|
|
540
|
+
private queuedRunDispatchTimer: ReturnType<typeof setTimeout> | undefined;
|
|
525
541
|
private readonly outcomes: Map<string, TeamOutcome> = new Map();
|
|
526
542
|
private readonly outcomeFragments: Map<string, TeamOutcomeFragment> =
|
|
527
543
|
new Map();
|
|
@@ -707,6 +723,7 @@ export class AgentTeamsRuntime {
|
|
|
707
723
|
}
|
|
708
724
|
|
|
709
725
|
hydrateState(state: TeamRuntimeState): void {
|
|
726
|
+
this.clearQueuedRunDispatchTimer();
|
|
710
727
|
this.tasks.clear();
|
|
711
728
|
for (const task of state.tasks) {
|
|
712
729
|
this.tasks.set(task.id, { ...task });
|
|
@@ -851,7 +868,10 @@ export class AgentTeamsRuntime {
|
|
|
851
868
|
},
|
|
852
869
|
};
|
|
853
870
|
|
|
854
|
-
const agent =
|
|
871
|
+
const agent = new SessionRuntime(wrappedConfig);
|
|
872
|
+
if (wrappedConfig.onEvent) {
|
|
873
|
+
agent.subscribeEvents(wrappedConfig.onEvent);
|
|
874
|
+
}
|
|
855
875
|
const teammate: TeamMemberState = {
|
|
856
876
|
agentId,
|
|
857
877
|
role: "teammate",
|
|
@@ -1038,12 +1058,14 @@ export class AgentTeamsRuntime {
|
|
|
1038
1058
|
error: err,
|
|
1039
1059
|
messages: member.agent.getMessages(),
|
|
1040
1060
|
});
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1061
|
+
if (!isIntentionalShutdownAbort(member, err)) {
|
|
1062
|
+
this.appendMissionLog({
|
|
1063
|
+
agentId,
|
|
1064
|
+
taskId: options?.taskId,
|
|
1065
|
+
kind: "error",
|
|
1066
|
+
summary: err.message,
|
|
1067
|
+
});
|
|
1068
|
+
}
|
|
1047
1069
|
throw err;
|
|
1048
1070
|
} finally {
|
|
1049
1071
|
member.runningCount--;
|
|
@@ -1091,11 +1113,19 @@ export class AgentTeamsRuntime {
|
|
|
1091
1113
|
}
|
|
1092
1114
|
|
|
1093
1115
|
private dispatchQueuedRuns(): void {
|
|
1116
|
+
this.clearQueuedRunDispatchTimer();
|
|
1117
|
+
let nextDelayedAttemptAt: Date | undefined;
|
|
1094
1118
|
while (
|
|
1095
1119
|
this.countActiveRuns() < this.maxConcurrentRuns &&
|
|
1096
1120
|
this.runQueue.length > 0
|
|
1097
1121
|
) {
|
|
1098
|
-
const
|
|
1122
|
+
const nextRun = this.selectNextDispatchableQueuedRun();
|
|
1123
|
+
nextDelayedAttemptAt = nextRun.nextDelayedAttemptAt;
|
|
1124
|
+
const nextRunIndex = nextRun.index;
|
|
1125
|
+
if (nextRunIndex < 0) {
|
|
1126
|
+
this.scheduleQueuedRunDispatch(nextDelayedAttemptAt);
|
|
1127
|
+
return;
|
|
1128
|
+
}
|
|
1099
1129
|
const [runId] = this.runQueue.splice(nextRunIndex, 1);
|
|
1100
1130
|
const run = runId ? this.runs.get(runId) : undefined;
|
|
1101
1131
|
if (!run || run.status !== "queued") {
|
|
@@ -1103,22 +1133,53 @@ export class AgentTeamsRuntime {
|
|
|
1103
1133
|
}
|
|
1104
1134
|
void this.executeQueuedRun(run);
|
|
1105
1135
|
}
|
|
1136
|
+
this.scheduleQueuedRunDispatch(nextDelayedAttemptAt);
|
|
1106
1137
|
}
|
|
1107
1138
|
|
|
1108
|
-
private
|
|
1109
|
-
|
|
1139
|
+
private selectNextDispatchableQueuedRun(): {
|
|
1140
|
+
index: number;
|
|
1141
|
+
nextDelayedAttemptAt?: Date;
|
|
1142
|
+
} {
|
|
1143
|
+
let selectedIndex = -1;
|
|
1110
1144
|
let bestPriority = Number.NEGATIVE_INFINITY;
|
|
1145
|
+
let nextDelayedAttemptAt: Date | undefined;
|
|
1146
|
+
const now = Date.now();
|
|
1111
1147
|
for (let index = 0; index < this.runQueue.length; index++) {
|
|
1112
1148
|
const run = this.runs.get(this.runQueue[index]);
|
|
1113
1149
|
if (!run || run.status !== "queued") {
|
|
1114
1150
|
continue;
|
|
1115
1151
|
}
|
|
1152
|
+
if (run.nextAttemptAt && run.nextAttemptAt.getTime() > now) {
|
|
1153
|
+
if (!nextDelayedAttemptAt || run.nextAttemptAt < nextDelayedAttemptAt) {
|
|
1154
|
+
nextDelayedAttemptAt = run.nextAttemptAt;
|
|
1155
|
+
}
|
|
1156
|
+
continue;
|
|
1157
|
+
}
|
|
1116
1158
|
if (run.priority > bestPriority) {
|
|
1117
1159
|
bestPriority = run.priority;
|
|
1118
1160
|
selectedIndex = index;
|
|
1119
1161
|
}
|
|
1120
1162
|
}
|
|
1121
|
-
return selectedIndex;
|
|
1163
|
+
return { index: selectedIndex, nextDelayedAttemptAt };
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1166
|
+
private scheduleQueuedRunDispatch(nextAttemptAt: Date | undefined): void {
|
|
1167
|
+
if (!nextAttemptAt) {
|
|
1168
|
+
return;
|
|
1169
|
+
}
|
|
1170
|
+
const delayMs = Math.max(0, nextAttemptAt.getTime() - Date.now());
|
|
1171
|
+
this.queuedRunDispatchTimer = setTimeout(() => {
|
|
1172
|
+
this.queuedRunDispatchTimer = undefined;
|
|
1173
|
+
this.dispatchQueuedRuns();
|
|
1174
|
+
}, delayMs);
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1177
|
+
private clearQueuedRunDispatchTimer(): void {
|
|
1178
|
+
if (!this.queuedRunDispatchTimer) {
|
|
1179
|
+
return;
|
|
1180
|
+
}
|
|
1181
|
+
clearTimeout(this.queuedRunDispatchTimer);
|
|
1182
|
+
this.queuedRunDispatchTimer = undefined;
|
|
1122
1183
|
}
|
|
1123
1184
|
|
|
1124
1185
|
private countActiveRuns(): number {
|
|
@@ -1134,6 +1195,8 @@ export class AgentTeamsRuntime {
|
|
|
1134
1195
|
private async executeQueuedRun(
|
|
1135
1196
|
run: TeamRunRecord & { result?: AgentResult },
|
|
1136
1197
|
): Promise<void> {
|
|
1198
|
+
const recoveredRun = run.currentActivity === RECOVERED_QUEUED_ACTIVITY;
|
|
1199
|
+
run.nextAttemptAt = undefined;
|
|
1137
1200
|
run.status = "running";
|
|
1138
1201
|
run.startedAt = new Date();
|
|
1139
1202
|
run.heartbeatAt = new Date();
|
|
@@ -1148,7 +1211,10 @@ export class AgentTeamsRuntime {
|
|
|
1148
1211
|
}, 2000);
|
|
1149
1212
|
|
|
1150
1213
|
try {
|
|
1151
|
-
const
|
|
1214
|
+
const runMessage = recoveredRun
|
|
1215
|
+
? buildRecoveredRunMessage(run)
|
|
1216
|
+
: run.message;
|
|
1217
|
+
const result = await this.routeToTeammate(run.agentId, runMessage, {
|
|
1152
1218
|
taskId: run.taskId,
|
|
1153
1219
|
continueConversation: run.continueConversation,
|
|
1154
1220
|
});
|
|
@@ -1164,7 +1230,16 @@ export class AgentTeamsRuntime {
|
|
|
1164
1230
|
: String(error ?? "Unknown error");
|
|
1165
1231
|
run.error = message;
|
|
1166
1232
|
run.endedAt = new Date();
|
|
1167
|
-
|
|
1233
|
+
const member = this.members.get(run.agentId);
|
|
1234
|
+
if (isIntentionalShutdownAbort(member, error)) {
|
|
1235
|
+
run.status = "cancelled";
|
|
1236
|
+
run.currentActivity = "cancelled";
|
|
1237
|
+
this.emitEvent({
|
|
1238
|
+
type: TeamMessageType.RunCancelled,
|
|
1239
|
+
run: { ...run },
|
|
1240
|
+
reason: message,
|
|
1241
|
+
});
|
|
1242
|
+
} else if (run.retryCount < run.maxRetries) {
|
|
1168
1243
|
run.retryCount++;
|
|
1169
1244
|
run.status = "queued";
|
|
1170
1245
|
run.nextAttemptAt = new Date(
|
|
@@ -1215,7 +1290,7 @@ export class AgentTeamsRuntime {
|
|
|
1215
1290
|
if (!run) {
|
|
1216
1291
|
throw new Error(`Run "${runId}" was not found`);
|
|
1217
1292
|
}
|
|
1218
|
-
while (run.status === "running") {
|
|
1293
|
+
while (run.status === "queued" || run.status === "running") {
|
|
1219
1294
|
await sleep(pollIntervalMs);
|
|
1220
1295
|
}
|
|
1221
1296
|
return { ...run };
|
|
@@ -1256,6 +1331,45 @@ export class AgentTeamsRuntime {
|
|
|
1256
1331
|
return { ...run };
|
|
1257
1332
|
}
|
|
1258
1333
|
|
|
1334
|
+
recoverActiveRuns(reason = "runtime_recovered"): TeamRunRecord[] {
|
|
1335
|
+
const recovered: TeamRunRecord[] = [];
|
|
1336
|
+
for (const run of this.runs.values()) {
|
|
1337
|
+
if (!["queued", "running"].includes(run.status)) {
|
|
1338
|
+
continue;
|
|
1339
|
+
}
|
|
1340
|
+
|
|
1341
|
+
const member = this.members.get(run.agentId);
|
|
1342
|
+
if (!member || member.role !== "teammate" || !member.agent) {
|
|
1343
|
+
run.status = "interrupted";
|
|
1344
|
+
run.error = "teammate_unavailable_after_recovery";
|
|
1345
|
+
run.endedAt = new Date();
|
|
1346
|
+
run.currentActivity = "interrupted";
|
|
1347
|
+
this.emitEvent({
|
|
1348
|
+
type: TeamMessageType.RunInterrupted,
|
|
1349
|
+
run: { ...run },
|
|
1350
|
+
reason: run.error,
|
|
1351
|
+
});
|
|
1352
|
+
continue;
|
|
1353
|
+
}
|
|
1354
|
+
|
|
1355
|
+
const now = new Date();
|
|
1356
|
+
run.status = "queued";
|
|
1357
|
+
run.error = undefined;
|
|
1358
|
+
run.endedAt = undefined;
|
|
1359
|
+
run.heartbeatAt = now;
|
|
1360
|
+
run.lastProgressAt = now;
|
|
1361
|
+
run.lastProgressMessage = reason;
|
|
1362
|
+
run.currentActivity = RECOVERED_QUEUED_ACTIVITY;
|
|
1363
|
+
if (!this.runQueue.includes(run.id)) {
|
|
1364
|
+
this.runQueue.push(run.id);
|
|
1365
|
+
}
|
|
1366
|
+
recovered.push({ ...run });
|
|
1367
|
+
this.emitEvent({ type: TeamMessageType.RunQueued, run: { ...run } });
|
|
1368
|
+
}
|
|
1369
|
+
this.dispatchQueuedRuns();
|
|
1370
|
+
return recovered;
|
|
1371
|
+
}
|
|
1372
|
+
|
|
1259
1373
|
markStaleRunsInterrupted(reason = "runtime_recovered"): TeamRunRecord[] {
|
|
1260
1374
|
const interrupted: TeamRunRecord[] = [];
|
|
1261
1375
|
for (const run of this.runs.values()) {
|
|
@@ -1274,6 +1388,7 @@ export class AgentTeamsRuntime {
|
|
|
1274
1388
|
});
|
|
1275
1389
|
}
|
|
1276
1390
|
this.runQueue.length = 0;
|
|
1391
|
+
this.clearQueuedRunDispatchTimer();
|
|
1277
1392
|
return interrupted;
|
|
1278
1393
|
}
|
|
1279
1394
|
|
|
@@ -1513,6 +1628,7 @@ export class AgentTeamsRuntime {
|
|
|
1513
1628
|
this.missionLog.length = 0;
|
|
1514
1629
|
this.runs.clear();
|
|
1515
1630
|
this.runQueue.length = 0;
|
|
1631
|
+
this.clearQueuedRunDispatchTimer();
|
|
1516
1632
|
this.outcomes.clear();
|
|
1517
1633
|
this.outcomeFragments.clear();
|
|
1518
1634
|
|