@renxqoo/renx-code 0.0.4 → 0.0.5
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/bin/renx.cjs +16 -0
- package/package.json +2 -45
- package/src/agent/runtime/runtime.context-usage.test.ts +4 -5
- package/src/agent/runtime/runtime.error-handling.test.ts +4 -5
- package/src/agent/runtime/runtime.test.ts +7 -4
- package/src/agent/runtime/runtime.ts +3 -9
- package/src/agent/runtime/runtime.usage-forwarding.test.ts +4 -5
- package/src/agent/runtime/source-modules.test.ts +16 -35
- package/src/agent/runtime/source-modules.ts +17 -0
- package/vendor/agent-root/src/agent/ENTERPRISE_ACCEPTANCE_CHECKLIST.md +95 -0
- package/vendor/agent-root/src/agent/ENTERPRISE_REALTIME.html +1345 -0
- package/vendor/agent-root/src/agent/ENTERPRISE_REALTIME.md +1353 -0
- package/vendor/agent-root/src/agent/ERROR_CONTRACT.md +60 -0
- package/vendor/agent-root/src/agent/TEST_COVERAGE_ANALYSIS.md +278 -0
- package/vendor/agent-root/src/agent/__test__/error-contract.test.ts +72 -0
- package/vendor/agent-root/src/agent/__test__/types.test.ts +137 -0
- package/vendor/agent-root/src/agent/agent/__test__/abort-runtime.test.ts +83 -0
- package/vendor/agent-root/src/agent/agent/__test__/callback-safety.test.ts +34 -0
- package/vendor/agent-root/src/agent/agent/__test__/compaction.test.ts +323 -0
- package/vendor/agent-root/src/agent/agent/__test__/concurrency.test.ts +290 -0
- package/vendor/agent-root/src/agent/agent/__test__/error-normalizer.test.ts +377 -0
- package/vendor/agent-root/src/agent/agent/__test__/error.test.ts +212 -0
- package/vendor/agent-root/src/agent/agent/__test__/fault-injection.test.ts +295 -0
- package/vendor/agent-root/src/agent/agent/__test__/index.test.ts +3607 -0
- package/vendor/agent-root/src/agent/agent/__test__/logger.test.ts +35 -0
- package/vendor/agent-root/src/agent/agent/__test__/message-utils.test.ts +517 -0
- package/vendor/agent-root/src/agent/agent/__test__/telemetry.test.ts +97 -0
- package/vendor/agent-root/src/agent/agent/__test__/timeout-budget.test.ts +479 -0
- package/vendor/agent-root/src/agent/agent/__test__/tool-call-merge.test.ts +80 -0
- package/vendor/agent-root/src/agent/agent/__test__/tool-execution-ledger.test.ts +76 -0
- package/vendor/agent-root/src/agent/agent/__test__/write-buffer.test.ts +173 -0
- package/vendor/agent-root/src/agent/agent/__test__/write-file-session.test.ts +109 -0
- package/vendor/agent-root/src/agent/agent/abort-runtime.ts +71 -0
- package/vendor/agent-root/src/agent/agent/callback-safety.ts +33 -0
- package/vendor/agent-root/src/agent/agent/compaction.ts +291 -0
- package/vendor/agent-root/src/agent/agent/concurrency.ts +103 -0
- package/vendor/agent-root/src/agent/agent/error-normalizer.ts +190 -0
- package/vendor/agent-root/src/agent/agent/error.ts +198 -0
- package/vendor/agent-root/src/agent/agent/index.ts +1772 -0
- package/vendor/agent-root/src/agent/agent/logger.ts +65 -0
- package/vendor/agent-root/src/agent/agent/message-utils.ts +101 -0
- package/vendor/agent-root/src/agent/agent/stream-events.ts +61 -0
- package/vendor/agent-root/src/agent/agent/telemetry.ts +123 -0
- package/vendor/agent-root/src/agent/agent/timeout-budget.ts +227 -0
- package/vendor/agent-root/src/agent/agent/tool-call-merge.ts +111 -0
- package/vendor/agent-root/src/agent/agent/tool-execution-ledger.ts +164 -0
- package/vendor/agent-root/src/agent/agent/write-buffer.ts +188 -0
- package/vendor/agent-root/src/agent/agent/write-file-session.ts +238 -0
- package/vendor/agent-root/src/agent/app/__test__/agent-app-service.test.ts +1053 -0
- package/vendor/agent-root/src/agent/app/__test__/minimal-agent-application.test.ts +158 -0
- package/vendor/agent-root/src/agent/app/__test__/sqlite-agent-app-store.test.ts +437 -0
- package/vendor/agent-root/src/agent/app/agent-app-service.ts +748 -0
- package/vendor/agent-root/src/agent/app/contracts.ts +109 -0
- package/vendor/agent-root/src/agent/app/index.ts +5 -0
- package/vendor/agent-root/src/agent/app/minimal-agent-application.ts +151 -0
- package/vendor/agent-root/src/agent/app/ports.ts +72 -0
- package/vendor/agent-root/src/agent/app/sqlite-agent-app-store.ts +1182 -0
- package/vendor/agent-root/src/agent/app/sqlite-client.ts +177 -0
- package/vendor/agent-root/src/agent/docs/cli-app-layer/00-README.md +36 -0
- package/vendor/agent-root/src/agent/docs/cli-app-layer/01-scope-and-goals.md +33 -0
- package/vendor/agent-root/src/agent/docs/cli-app-layer/02-architecture-overview.md +40 -0
- package/vendor/agent-root/src/agent/docs/cli-app-layer/03-domain-model-and-contracts.md +91 -0
- package/vendor/agent-root/src/agent/docs/cli-app-layer/04-ports-and-interfaces.md +116 -0
- package/vendor/agent-root/src/agent/docs/cli-app-layer/05-run-orchestration-and-state-machine.md +52 -0
- package/vendor/agent-root/src/agent/docs/cli-app-layer/06-cli-commands-and-ux.md +53 -0
- package/vendor/agent-root/src/agent/docs/cli-app-layer/07-storage-design-local.md +52 -0
- package/vendor/agent-root/src/agent/docs/cli-app-layer/08-error-and-observability.md +40 -0
- package/vendor/agent-root/src/agent/docs/cli-app-layer/09-security-and-policy-boundary.md +19 -0
- package/vendor/agent-root/src/agent/docs/cli-app-layer/10-test-plan-and-acceptance.md +28 -0
- package/vendor/agent-root/src/agent/docs/cli-app-layer/11-implementation-phases.md +26 -0
- package/vendor/agent-root/src/agent/docs/cli-app-layer/12-open-questions-and-risks.md +30 -0
- package/vendor/agent-root/src/agent/docs/cli-app-layer/13-sqlite-schema-fields-and-rationale.md +567 -0
- package/vendor/agent-root/src/agent/docs/cli-app-layer/14-project-flow-mermaid.md +583 -0
- package/vendor/agent-root/src/agent/docs/cli-app-layer/15-openclaw-style-project-blueprint.md +972 -0
- package/vendor/agent-root/src/agent/error-contract.ts +154 -0
- package/vendor/agent-root/src/agent/prompts/system.ts +246 -0
- package/vendor/agent-root/src/agent/prompts/system1.ts +208 -0
- package/vendor/agent-root/src/agent/storage/__test__/file-history-store.test.ts +98 -0
- package/vendor/agent-root/src/agent/storage/file-history-store.ts +313 -0
- package/vendor/agent-root/src/agent/storage/file-storage-config.ts +94 -0
- package/vendor/agent-root/src/agent/storage/file-system.ts +31 -0
- package/vendor/agent-root/src/agent/storage/file-write-service.ts +21 -0
- package/vendor/agent-root/src/agent/tool/__test__/base-tool.test.ts +413 -0
- package/vendor/agent-root/src/agent/tool/__test__/bash-policy.test.ts +356 -0
- package/vendor/agent-root/src/agent/tool/__test__/bash.mocked-coverage.test.ts +375 -0
- package/vendor/agent-root/src/agent/tool/__test__/bash.test.ts +372 -0
- package/vendor/agent-root/src/agent/tool/__test__/error.test.ts +108 -0
- package/vendor/agent-root/src/agent/tool/__test__/file-edit-tool.test.ts +258 -0
- package/vendor/agent-root/src/agent/tool/__test__/file-history-tools.test.ts +121 -0
- package/vendor/agent-root/src/agent/tool/__test__/file-read-tool.test.ts +210 -0
- package/vendor/agent-root/src/agent/tool/__test__/glob.test.ts +139 -0
- package/vendor/agent-root/src/agent/tool/__test__/grep.mocked-coverage.test.ts +456 -0
- package/vendor/agent-root/src/agent/tool/__test__/grep.test.ts +192 -0
- package/vendor/agent-root/src/agent/tool/__test__/lsp.test.ts +300 -0
- package/vendor/agent-root/src/agent/tool/__test__/outside-workspace-confirmation.test.ts +214 -0
- package/vendor/agent-root/src/agent/tool/__test__/path-security.test.ts +336 -0
- package/vendor/agent-root/src/agent/tool/__test__/skill-loader.test.ts +494 -0
- package/vendor/agent-root/src/agent/tool/__test__/skill-parser.test.ts +543 -0
- package/vendor/agent-root/src/agent/tool/__test__/skill-tool.test.ts +172 -0
- package/vendor/agent-root/src/agent/tool/__test__/task-concurrency-and-version.test.ts +116 -0
- package/vendor/agent-root/src/agent/tool/__test__/task-create-get-list-update.test.ts +267 -0
- package/vendor/agent-root/src/agent/tool/__test__/task-create.test.ts +519 -0
- package/vendor/agent-root/src/agent/tool/__test__/task-errors.test.ts +225 -0
- package/vendor/agent-root/src/agent/tool/__test__/task-output-blocking.test.ts +223 -0
- package/vendor/agent-root/src/agent/tool/__test__/task-output.test.ts +184 -0
- package/vendor/agent-root/src/agent/tool/__test__/task-parent-abort.test.ts +287 -0
- package/vendor/agent-root/src/agent/tool/__test__/task-real-runner-adapter.test.ts +190 -0
- package/vendor/agent-root/src/agent/tool/__test__/task-run-lifecycle.test.ts +352 -0
- package/vendor/agent-root/src/agent/tool/__test__/task-store-runner-branches.test.ts +395 -0
- package/vendor/agent-root/src/agent/tool/__test__/task-store.test.ts +391 -0
- package/vendor/agent-root/src/agent/tool/__test__/task-subagent-config-integration.test.ts +176 -0
- package/vendor/agent-root/src/agent/tool/__test__/task-subagent-config.test.ts +68 -0
- package/vendor/agent-root/src/agent/tool/__test__/task-tools-core-edges.test.ts +630 -0
- package/vendor/agent-root/src/agent/tool/__test__/task-tools-runtime-edges.test.ts +732 -0
- package/vendor/agent-root/src/agent/tool/__test__/task-types.test.ts +494 -0
- package/vendor/agent-root/src/agent/tool/__test__/task-utils-branches.test.ts +175 -0
- package/vendor/agent-root/src/agent/tool/__test__/tool-manager.test.ts +505 -0
- package/vendor/agent-root/src/agent/tool/__test__/types.test.ts +55 -0
- package/vendor/agent-root/src/agent/tool/__test__/web-fetch.test.ts +244 -0
- package/vendor/agent-root/src/agent/tool/__test__/web-search.test.ts +290 -0
- package/vendor/agent-root/src/agent/tool/__test__/write-file.test.ts +368 -0
- package/vendor/agent-root/src/agent/tool/base-tool.ts +345 -0
- package/vendor/agent-root/src/agent/tool/bash-policy.ts +636 -0
- package/vendor/agent-root/src/agent/tool/bash.ts +688 -0
- package/vendor/agent-root/src/agent/tool/error.ts +131 -0
- package/vendor/agent-root/src/agent/tool/file-edit-tool.ts +264 -0
- package/vendor/agent-root/src/agent/tool/file-history-list.ts +103 -0
- package/vendor/agent-root/src/agent/tool/file-history-restore.ts +149 -0
- package/vendor/agent-root/src/agent/tool/file-read-tool.ts +211 -0
- package/vendor/agent-root/src/agent/tool/glob.ts +171 -0
- package/vendor/agent-root/src/agent/tool/grep.ts +496 -0
- package/vendor/agent-root/src/agent/tool/lsp.ts +481 -0
- package/vendor/agent-root/src/agent/tool/path-security.ts +117 -0
- package/vendor/agent-root/src/agent/tool/search/common.ts +153 -0
- package/vendor/agent-root/src/agent/tool/skill/index.ts +13 -0
- package/vendor/agent-root/src/agent/tool/skill/loader.ts +229 -0
- package/vendor/agent-root/src/agent/tool/skill/parser.ts +124 -0
- package/vendor/agent-root/src/agent/tool/skill/types.ts +27 -0
- package/vendor/agent-root/src/agent/tool/skill-tool.ts +143 -0
- package/vendor/agent-root/src/agent/tool/task-create.ts +186 -0
- package/vendor/agent-root/src/agent/tool/task-errors.ts +42 -0
- package/vendor/agent-root/src/agent/tool/task-get.ts +116 -0
- package/vendor/agent-root/src/agent/tool/task-graph.ts +78 -0
- package/vendor/agent-root/src/agent/tool/task-list.ts +141 -0
- package/vendor/agent-root/src/agent/tool/task-mock-runner-adapter.ts +232 -0
- package/vendor/agent-root/src/agent/tool/task-output.ts +223 -0
- package/vendor/agent-root/src/agent/tool/task-parent-abort.ts +115 -0
- package/vendor/agent-root/src/agent/tool/task-real-runner-adapter.ts +336 -0
- package/vendor/agent-root/src/agent/tool/task-runner-adapter.ts +55 -0
- package/vendor/agent-root/src/agent/tool/task-stop.ts +187 -0
- package/vendor/agent-root/src/agent/tool/task-store.ts +217 -0
- package/vendor/agent-root/src/agent/tool/task-subagent-config.ts +149 -0
- package/vendor/agent-root/src/agent/tool/task-types.ts +264 -0
- package/vendor/agent-root/src/agent/tool/task-update.ts +315 -0
- package/vendor/agent-root/src/agent/tool/task.ts +209 -0
- package/vendor/agent-root/src/agent/tool/tool-manager.ts +362 -0
- package/vendor/agent-root/src/agent/tool/tool-prompts.ts +242 -0
- package/vendor/agent-root/src/agent/tool/types.ts +116 -0
- package/vendor/agent-root/src/agent/tool/web-fetch.ts +227 -0
- package/vendor/agent-root/src/agent/tool/web-search.ts +208 -0
- package/vendor/agent-root/src/agent/tool/write-file.ts +497 -0
- package/vendor/agent-root/src/agent/types.ts +232 -0
- package/vendor/agent-root/src/agent/utils/__tests__/index.test.ts +18 -0
- package/vendor/agent-root/src/agent/utils/__tests__/message-utils.test.ts +610 -0
- package/vendor/agent-root/src/agent/utils/__tests__/message.test.ts +223 -0
- package/vendor/agent-root/src/agent/utils/__tests__/token.test.ts +42 -0
- package/vendor/agent-root/src/agent/utils/index.ts +16 -0
- package/vendor/agent-root/src/agent/utils/message.ts +171 -0
- package/vendor/agent-root/src/agent/utils/token.ts +28 -0
- package/vendor/agent-root/src/config/__tests__/load-config-to-env.test.ts +129 -0
- package/vendor/agent-root/src/config/__tests__/loader.test.ts +247 -0
- package/vendor/agent-root/src/config/__tests__/runtime.test.ts +88 -0
- package/vendor/agent-root/src/config/index.ts +54 -0
- package/vendor/agent-root/src/config/loader.ts +431 -0
- package/vendor/agent-root/src/config/paths.ts +30 -0
- package/vendor/agent-root/src/config/runtime.ts +163 -0
- package/vendor/agent-root/src/config/types.ts +70 -0
- package/vendor/agent-root/src/logger/index.ts +57 -0
- package/vendor/agent-root/src/logger/logger.ts +819 -0
- package/vendor/agent-root/src/logger/types.ts +150 -0
- package/vendor/agent-root/src/providers/__tests__/errors.test.ts +441 -0
- package/vendor/agent-root/src/providers/__tests__/index.test.ts +16 -0
- package/vendor/agent-root/src/providers/__tests__/openai-compatible.options.test.ts +318 -0
- package/vendor/agent-root/src/providers/__tests__/openai-compatible.test.ts +600 -0
- package/vendor/agent-root/src/providers/__tests__/registry.test.ts +449 -0
- package/vendor/agent-root/src/providers/__tests__/responses-adapter.test.ts +298 -0
- package/vendor/agent-root/src/providers/adapters/__tests__/anthropic.test.ts +354 -0
- package/vendor/agent-root/src/providers/adapters/__tests__/kimi.test.ts +58 -0
- package/vendor/agent-root/src/providers/adapters/__tests__/standard.test.ts +261 -0
- package/vendor/agent-root/src/providers/adapters/anthropic.ts +572 -0
- package/vendor/agent-root/src/providers/adapters/base.ts +131 -0
- package/vendor/agent-root/src/providers/adapters/kimi.ts +48 -0
- package/vendor/agent-root/src/providers/adapters/responses.ts +732 -0
- package/vendor/agent-root/src/providers/adapters/standard.ts +120 -0
- package/vendor/agent-root/src/providers/http/__tests__/client.timeout.test.ts +313 -0
- package/vendor/agent-root/src/providers/http/client.ts +289 -0
- package/vendor/agent-root/src/providers/http/stream-parser.ts +109 -0
- package/vendor/agent-root/src/providers/index.ts +76 -0
- package/vendor/agent-root/src/providers/kimi-headers.ts +177 -0
- package/vendor/agent-root/src/providers/openai-compatible.ts +387 -0
- package/vendor/agent-root/src/providers/registry/model-config.ts +230 -0
- package/vendor/agent-root/src/providers/registry/provider-factory.ts +123 -0
- package/vendor/agent-root/src/providers/registry.ts +135 -0
- package/vendor/agent-root/src/providers/types/api.ts +284 -0
- package/vendor/agent-root/src/providers/types/config.ts +58 -0
- package/vendor/agent-root/src/providers/types/errors.ts +323 -0
- package/vendor/agent-root/src/providers/types/index.ts +72 -0
- package/vendor/agent-root/src/providers/types/provider.ts +45 -0
- package/vendor/agent-root/src/providers/types/registry.ts +88 -0
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
import * as fs from 'node:fs/promises';
|
|
2
|
+
import * as path from 'node:path';
|
|
3
|
+
import type { ToolExecutionContext } from './types';
|
|
4
|
+
import { TaskStore } from './task-store';
|
|
5
|
+
import {
|
|
6
|
+
createAgentId,
|
|
7
|
+
isAgentRunTerminal,
|
|
8
|
+
safeJsonClone,
|
|
9
|
+
type AgentRunEntity,
|
|
10
|
+
} from './task-types';
|
|
11
|
+
import type { StartAgentInput, SubagentRunnerAdapter } from './task-runner-adapter';
|
|
12
|
+
|
|
13
|
+
export interface InProcessMockRunnerAdapterOptions {
|
|
14
|
+
completionDelayMs?: number;
|
|
15
|
+
now?: () => number;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function createMockOutput(run: AgentRunEntity): string {
|
|
19
|
+
const preview = run.prompt.trim().slice(0, 120);
|
|
20
|
+
if (!preview) {
|
|
21
|
+
return `Subagent ${run.agentId} completed`;
|
|
22
|
+
}
|
|
23
|
+
return `Subagent ${run.agentId} completed: ${preview}`;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export class InProcessMockRunnerAdapter implements SubagentRunnerAdapter {
|
|
27
|
+
private readonly completionDelayMs: number;
|
|
28
|
+
private readonly now: () => number;
|
|
29
|
+
private readonly timers = new Map<string, NodeJS.Timeout>();
|
|
30
|
+
|
|
31
|
+
constructor(
|
|
32
|
+
private readonly store: TaskStore,
|
|
33
|
+
options: InProcessMockRunnerAdapterOptions = {}
|
|
34
|
+
) {
|
|
35
|
+
this.completionDelayMs =
|
|
36
|
+
typeof options.completionDelayMs === 'number' && options.completionDelayMs > 0
|
|
37
|
+
? options.completionDelayMs
|
|
38
|
+
: 30;
|
|
39
|
+
this.now = options.now || Date.now;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async start(
|
|
43
|
+
namespace: string,
|
|
44
|
+
input: StartAgentInput,
|
|
45
|
+
context?: ToolExecutionContext
|
|
46
|
+
): Promise<AgentRunEntity> {
|
|
47
|
+
if (input.resume) {
|
|
48
|
+
const resumed = await this.resumeRun(namespace, input.resume);
|
|
49
|
+
if (!resumed) {
|
|
50
|
+
throw new Error(`AGENT_RUN_NOT_FOUND: ${input.resume}`);
|
|
51
|
+
}
|
|
52
|
+
return resumed;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const createdAt = this.now();
|
|
56
|
+
const agentId = createAgentId();
|
|
57
|
+
const outputFile = this.buildOutputFilePath(namespace, agentId);
|
|
58
|
+
const run: AgentRunEntity = {
|
|
59
|
+
agentId,
|
|
60
|
+
status: 'running',
|
|
61
|
+
subagentType: input.subagentType,
|
|
62
|
+
prompt: input.prompt,
|
|
63
|
+
description: input.description,
|
|
64
|
+
model: input.model,
|
|
65
|
+
maxTurns: input.maxTurns,
|
|
66
|
+
allowedTools: input.allowedTools,
|
|
67
|
+
linkedTaskId: input.linkedTaskId,
|
|
68
|
+
createdAt,
|
|
69
|
+
startedAt: createdAt,
|
|
70
|
+
updatedAt: createdAt,
|
|
71
|
+
progress: input.runInBackground ? 0 : 100,
|
|
72
|
+
outputFile: input.runInBackground ? outputFile : undefined,
|
|
73
|
+
metadata: {
|
|
74
|
+
...(input.metadata || {}),
|
|
75
|
+
...(input.systemPrompt ? { systemPrompt: input.systemPrompt } : {}),
|
|
76
|
+
},
|
|
77
|
+
version: 1,
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
await this.store.updateState(namespace, (state) => {
|
|
81
|
+
state.agentRuns[run.agentId] = safeJsonClone(run);
|
|
82
|
+
return null;
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
await context?.onChunk?.({
|
|
86
|
+
type: 'info',
|
|
87
|
+
content: `subagent started: ${run.agentId}`,
|
|
88
|
+
data: `subagent started: ${run.agentId}`,
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
if (input.runInBackground) {
|
|
92
|
+
this.scheduleCompletion(namespace, run.agentId);
|
|
93
|
+
return run;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const completed = await this.completeRun(namespace, run.agentId);
|
|
97
|
+
return completed || run;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
async poll(namespace: string, agentId: string): Promise<AgentRunEntity | null> {
|
|
101
|
+
const state = await this.store.getState(namespace);
|
|
102
|
+
return safeJsonClone(state.agentRuns[agentId] || null);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
async cancel(
|
|
106
|
+
namespace: string,
|
|
107
|
+
agentId: string,
|
|
108
|
+
reason?: string
|
|
109
|
+
): Promise<AgentRunEntity | null> {
|
|
110
|
+
const timerKey = this.timerKey(namespace, agentId);
|
|
111
|
+
const timer = this.timers.get(timerKey);
|
|
112
|
+
if (timer) {
|
|
113
|
+
clearTimeout(timer);
|
|
114
|
+
this.timers.delete(timerKey);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const result = await this.store.updateState(namespace, (state) => {
|
|
118
|
+
const run = state.agentRuns[agentId];
|
|
119
|
+
if (!run) {
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
if (isAgentRunTerminal(run.status)) {
|
|
123
|
+
return safeJsonClone(run);
|
|
124
|
+
}
|
|
125
|
+
run.status = 'cancelled';
|
|
126
|
+
run.error = reason || 'Cancelled by task_stop';
|
|
127
|
+
run.progress = run.progress || 0;
|
|
128
|
+
run.endedAt = this.now();
|
|
129
|
+
run.updatedAt = this.now();
|
|
130
|
+
run.version += 1;
|
|
131
|
+
return safeJsonClone(run);
|
|
132
|
+
});
|
|
133
|
+
return result.result;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
private async resumeRun(namespace: string, resumeId: string): Promise<AgentRunEntity | null> {
|
|
137
|
+
const result = await this.store.updateState(namespace, (state) => {
|
|
138
|
+
const run = state.agentRuns[resumeId];
|
|
139
|
+
if (!run) {
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
if (isAgentRunTerminal(run.status) || run.status === 'running') {
|
|
143
|
+
return safeJsonClone(run);
|
|
144
|
+
}
|
|
145
|
+
run.status = 'running';
|
|
146
|
+
run.updatedAt = this.now();
|
|
147
|
+
run.version += 1;
|
|
148
|
+
return safeJsonClone(run);
|
|
149
|
+
});
|
|
150
|
+
const resumed = result.result;
|
|
151
|
+
if (resumed && resumed.status === 'running') {
|
|
152
|
+
this.scheduleCompletion(namespace, resumed.agentId);
|
|
153
|
+
}
|
|
154
|
+
return resumed;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
private scheduleCompletion(namespace: string, agentId: string): void {
|
|
158
|
+
const timerKey = this.timerKey(namespace, agentId);
|
|
159
|
+
const existing = this.timers.get(timerKey);
|
|
160
|
+
if (existing) {
|
|
161
|
+
clearTimeout(existing);
|
|
162
|
+
}
|
|
163
|
+
const timer = setTimeout(() => {
|
|
164
|
+
void this.completeRun(namespace, agentId);
|
|
165
|
+
}, this.completionDelayMs);
|
|
166
|
+
this.timers.set(timerKey, timer);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
private async completeRun(namespace: string, agentId: string): Promise<AgentRunEntity | null> {
|
|
170
|
+
const timerKey = this.timerKey(namespace, agentId);
|
|
171
|
+
const timer = this.timers.get(timerKey);
|
|
172
|
+
if (timer) {
|
|
173
|
+
clearTimeout(timer);
|
|
174
|
+
this.timers.delete(timerKey);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const result = await this.store.updateState(namespace, (state) => {
|
|
178
|
+
const run = state.agentRuns[agentId];
|
|
179
|
+
if (!run) {
|
|
180
|
+
return null;
|
|
181
|
+
}
|
|
182
|
+
if (isAgentRunTerminal(run.status)) {
|
|
183
|
+
return safeJsonClone(run);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const prompt = run.prompt.toLowerCase();
|
|
187
|
+
if (prompt.includes('[task_fail]')) {
|
|
188
|
+
run.status = 'failed';
|
|
189
|
+
run.error = 'Subagent mock failure requested by prompt token [TASK_FAIL]';
|
|
190
|
+
} else if (prompt.includes('[task_pause]')) {
|
|
191
|
+
run.status = 'paused';
|
|
192
|
+
} else if (prompt.includes('[task_timeout]')) {
|
|
193
|
+
run.status = 'timed_out';
|
|
194
|
+
run.error = 'Subagent mock timeout requested by prompt token [TASK_TIMEOUT]';
|
|
195
|
+
} else {
|
|
196
|
+
run.status = 'completed';
|
|
197
|
+
run.output = createMockOutput(run);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
run.progress = run.status === 'completed' ? 100 : run.progress || 0;
|
|
201
|
+
run.endedAt = this.now();
|
|
202
|
+
run.updatedAt = this.now();
|
|
203
|
+
run.version += 1;
|
|
204
|
+
|
|
205
|
+
return safeJsonClone(run);
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
const completed = result.result;
|
|
209
|
+
if (completed?.outputFile) {
|
|
210
|
+
await this.persistOutputFile(completed.outputFile, completed);
|
|
211
|
+
}
|
|
212
|
+
return completed;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
private async persistOutputFile(outputFile: string, run: AgentRunEntity): Promise<void> {
|
|
216
|
+
try {
|
|
217
|
+
await fs.mkdir(path.dirname(outputFile), { recursive: true });
|
|
218
|
+
const content = run.output || run.error || run.status;
|
|
219
|
+
await fs.writeFile(outputFile, content, 'utf8');
|
|
220
|
+
} catch {
|
|
221
|
+
// Persisting debug output must never block tool response.
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
private buildOutputFilePath(namespace: string, agentId: string): string {
|
|
226
|
+
return path.join(this.store.baseDir, 'logs', namespace, `${agentId}.log`);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
private timerKey(namespace: string, agentId: string): string {
|
|
230
|
+
return `${namespace}::${agentId}`;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { BaseTool, type ToolResult } from './base-tool';
|
|
3
|
+
import { buildTaskFailure, buildTaskSuccess } from './task-errors';
|
|
4
|
+
import { getTaskStore, type TaskStore } from './task-store';
|
|
5
|
+
import {
|
|
6
|
+
createUnconfiguredSubagentRunnerAdapter,
|
|
7
|
+
type SubagentRunnerAdapter,
|
|
8
|
+
} from './task-runner-adapter';
|
|
9
|
+
import { isAgentRunTerminal, safeJsonClone, type AgentRunEntity } from './task-types';
|
|
10
|
+
import type { ToolExecutionContext } from './types';
|
|
11
|
+
import { TASK_OUTPUT_DESCRIPTION } from './tool-prompts';
|
|
12
|
+
|
|
13
|
+
const blockSchema = z.preprocess((value) => {
|
|
14
|
+
if (typeof value === 'string') {
|
|
15
|
+
const normalized = value.trim().toLowerCase();
|
|
16
|
+
if (normalized === 'true') return true;
|
|
17
|
+
if (normalized === 'false') return false;
|
|
18
|
+
}
|
|
19
|
+
return value;
|
|
20
|
+
}, z.boolean());
|
|
21
|
+
|
|
22
|
+
const schema = z
|
|
23
|
+
.object({
|
|
24
|
+
namespace: z.string().min(1).optional().describe('Optional task namespace'),
|
|
25
|
+
agent_id: z.string().min(1).optional().describe('Direct agent run id to query'),
|
|
26
|
+
task_id: z
|
|
27
|
+
.string()
|
|
28
|
+
.min(1)
|
|
29
|
+
.optional()
|
|
30
|
+
.describe('Planning task id used to resolve linked agent run'),
|
|
31
|
+
block: blockSchema.optional().describe('Wait for task completion before returning'),
|
|
32
|
+
timeout_ms: z
|
|
33
|
+
.number()
|
|
34
|
+
.int()
|
|
35
|
+
.min(1)
|
|
36
|
+
.max(30 * 60 * 1000)
|
|
37
|
+
.optional()
|
|
38
|
+
.describe('Timeout in milliseconds when blocking'),
|
|
39
|
+
poll_interval_ms: z
|
|
40
|
+
.number()
|
|
41
|
+
.int()
|
|
42
|
+
.min(20)
|
|
43
|
+
.max(5000)
|
|
44
|
+
.optional()
|
|
45
|
+
.describe('Polling interval in milliseconds'),
|
|
46
|
+
})
|
|
47
|
+
.strict();
|
|
48
|
+
|
|
49
|
+
type TaskOutputArgs = z.infer<typeof schema>;
|
|
50
|
+
|
|
51
|
+
export interface TaskOutputToolOptions {
|
|
52
|
+
store?: TaskStore;
|
|
53
|
+
runner?: SubagentRunnerAdapter;
|
|
54
|
+
defaultNamespace?: string;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async function sleep(ms: number, signal?: AbortSignal): Promise<void> {
|
|
58
|
+
if (signal?.aborted) {
|
|
59
|
+
throw new Error('TASK_OUTPUT_ABORTED: polling aborted');
|
|
60
|
+
}
|
|
61
|
+
await new Promise<void>((resolve, reject) => {
|
|
62
|
+
const timeout = setTimeout(() => {
|
|
63
|
+
signal?.removeEventListener('abort', onAbort);
|
|
64
|
+
resolve();
|
|
65
|
+
}, ms);
|
|
66
|
+
const onAbort = () => {
|
|
67
|
+
clearTimeout(timeout);
|
|
68
|
+
reject(new Error('TASK_OUTPUT_ABORTED: polling aborted'));
|
|
69
|
+
};
|
|
70
|
+
signal?.addEventListener('abort', onAbort, { once: true });
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function sanitizeTaskOutputRun(run: AgentRunEntity): AgentRunEntity {
|
|
75
|
+
const cloned = safeJsonClone(run);
|
|
76
|
+
if (cloned.status === 'completed') {
|
|
77
|
+
return cloned;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
delete cloned.output;
|
|
81
|
+
|
|
82
|
+
if (
|
|
83
|
+
(cloned.status === 'failed' ||
|
|
84
|
+
cloned.status === 'timed_out' ||
|
|
85
|
+
cloned.status === 'cancelled') &&
|
|
86
|
+
(!cloned.error || cloned.error.trim().length === 0)
|
|
87
|
+
) {
|
|
88
|
+
cloned.error = `Agent run ${cloned.status}`;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return cloned;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export class TaskOutputTool extends BaseTool<typeof schema> {
|
|
95
|
+
name = 'task_output';
|
|
96
|
+
description = TASK_OUTPUT_DESCRIPTION;
|
|
97
|
+
parameters = schema;
|
|
98
|
+
|
|
99
|
+
private readonly store: TaskStore;
|
|
100
|
+
private readonly runner: SubagentRunnerAdapter;
|
|
101
|
+
private readonly defaultNamespace?: string;
|
|
102
|
+
|
|
103
|
+
constructor(options: TaskOutputToolOptions = {}) {
|
|
104
|
+
super();
|
|
105
|
+
this.store = options.store || getTaskStore();
|
|
106
|
+
this.runner = options.runner || createUnconfiguredSubagentRunnerAdapter();
|
|
107
|
+
this.defaultNamespace = options.defaultNamespace;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
override getConcurrencyMode(): 'parallel-safe' {
|
|
111
|
+
return 'parallel-safe';
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
override getConcurrencyLockKey(args: TaskOutputArgs): string {
|
|
115
|
+
const namespace = args.namespace || this.defaultNamespace || 'default';
|
|
116
|
+
const target = args.agent_id || args.task_id || 'unknown';
|
|
117
|
+
return `taskns:${namespace}:agent:${target}`;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
async execute(args: TaskOutputArgs, context?: ToolExecutionContext): Promise<ToolResult> {
|
|
121
|
+
const namespace = args.namespace || this.defaultNamespace;
|
|
122
|
+
const normalizedNamespace = this.store.normalizeNamespace(namespace);
|
|
123
|
+
|
|
124
|
+
const resolvedAgentIdResult = await this.resolveAgentId(normalizedNamespace, args);
|
|
125
|
+
if (!resolvedAgentIdResult.ok) {
|
|
126
|
+
return buildTaskFailure(resolvedAgentIdResult.code, resolvedAgentIdResult.message, {
|
|
127
|
+
namespace: normalizedNamespace,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const agentId = resolvedAgentIdResult.agentId;
|
|
132
|
+
|
|
133
|
+
const shouldBlock = args.block !== undefined ? args.block : true;
|
|
134
|
+
const timeoutMs = args.timeout_ms !== undefined ? args.timeout_ms : 30000;
|
|
135
|
+
const pollIntervalMs = args.poll_interval_ms !== undefined ? args.poll_interval_ms : 200;
|
|
136
|
+
|
|
137
|
+
// Default semantics: block=true.
|
|
138
|
+
if (!shouldBlock) {
|
|
139
|
+
const run = await this.runner.poll(normalizedNamespace, agentId);
|
|
140
|
+
if (!run) {
|
|
141
|
+
return buildTaskFailure('AGENT_RUN_NOT_FOUND', `agent run not found: ${agentId}`, {
|
|
142
|
+
namespace: normalizedNamespace,
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
return buildTaskSuccess({
|
|
146
|
+
namespace: normalizedNamespace,
|
|
147
|
+
agent_run: sanitizeTaskOutputRun(run),
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const startedAt = Date.now();
|
|
152
|
+
while (Date.now() - startedAt < timeoutMs) {
|
|
153
|
+
const run = await this.runner.poll(normalizedNamespace, agentId);
|
|
154
|
+
if (!run) {
|
|
155
|
+
return buildTaskFailure('AGENT_RUN_NOT_FOUND', `agent run not found: ${agentId}`, {
|
|
156
|
+
namespace: normalizedNamespace,
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
if (isAgentRunTerminal(run.status)) {
|
|
160
|
+
return buildTaskSuccess({
|
|
161
|
+
namespace: normalizedNamespace,
|
|
162
|
+
agent_run: sanitizeTaskOutputRun(run),
|
|
163
|
+
waited_ms: Date.now() - startedAt,
|
|
164
|
+
completed: true,
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
await sleep(pollIntervalMs, context?.toolAbortSignal);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const latest = await this.runner.poll(normalizedNamespace, agentId);
|
|
171
|
+
if (!latest) {
|
|
172
|
+
return buildTaskFailure('AGENT_RUN_NOT_FOUND', `agent run not found: ${agentId}`, {
|
|
173
|
+
namespace: normalizedNamespace,
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
return buildTaskSuccess({
|
|
177
|
+
namespace: normalizedNamespace,
|
|
178
|
+
agent_run: sanitizeTaskOutputRun(latest),
|
|
179
|
+
waited_ms: Date.now() - startedAt,
|
|
180
|
+
completed: false,
|
|
181
|
+
timeout_hit: true,
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
private async resolveAgentId(
|
|
186
|
+
namespace: string,
|
|
187
|
+
args: TaskOutputArgs
|
|
188
|
+
): Promise<{ ok: true; agentId: string } | { ok: false; code: string; message: string }> {
|
|
189
|
+
if (args.agent_id) {
|
|
190
|
+
return { ok: true, agentId: args.agent_id };
|
|
191
|
+
}
|
|
192
|
+
if (!args.task_id) {
|
|
193
|
+
return {
|
|
194
|
+
ok: false,
|
|
195
|
+
code: 'TASK_OUTPUT_TARGET_REQUIRED',
|
|
196
|
+
message: 'agent_id or task_id is required',
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const state = await this.store.getState(namespace);
|
|
201
|
+
const task = state.tasks[args.task_id];
|
|
202
|
+
if (!task) {
|
|
203
|
+
return {
|
|
204
|
+
ok: false,
|
|
205
|
+
code: 'TASK_NOT_FOUND',
|
|
206
|
+
message: `task not found: ${args.task_id}`,
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
if (!task.agentId) {
|
|
210
|
+
return {
|
|
211
|
+
ok: false,
|
|
212
|
+
code: 'AGENT_RUN_NOT_FOUND',
|
|
213
|
+
message: `task has no linked agent run: ${args.task_id}`,
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
return {
|
|
217
|
+
ok: true,
|
|
218
|
+
agentId: task.agentId,
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
export default TaskOutputTool;
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import type { SubagentRunnerAdapter } from './task-runner-adapter';
|
|
2
|
+
import type { TaskStore } from './task-store';
|
|
3
|
+
import type { ToolExecutionContext } from './types';
|
|
4
|
+
|
|
5
|
+
export const PARENT_ABORT_REASON = 'Cancelled by parent agent abort';
|
|
6
|
+
|
|
7
|
+
interface ParentAbortCascadeParams {
|
|
8
|
+
context?: ToolExecutionContext;
|
|
9
|
+
namespace: string;
|
|
10
|
+
agentId: string;
|
|
11
|
+
linkedTaskId?: string;
|
|
12
|
+
runner: SubagentRunnerAdapter;
|
|
13
|
+
store: TaskStore;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
interface CancelLinkedTaskParams {
|
|
17
|
+
namespace: string;
|
|
18
|
+
linkedTaskId: string;
|
|
19
|
+
agentId: string;
|
|
20
|
+
agentStatus: string;
|
|
21
|
+
store: TaskStore;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function attachParentAbortCascade(params: ParentAbortCascadeParams): () => void {
|
|
25
|
+
const signal = params.context?.toolAbortSignal;
|
|
26
|
+
if (!signal) {
|
|
27
|
+
return () => {};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
let settled = false;
|
|
31
|
+
const onAbort = () => {
|
|
32
|
+
if (settled) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
settled = true;
|
|
36
|
+
void onParentAborted(params);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
|
40
|
+
if (signal.aborted) {
|
|
41
|
+
onAbort();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return () => {
|
|
45
|
+
signal.removeEventListener('abort', onAbort);
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async function onParentAborted(params: ParentAbortCascadeParams): Promise<void> {
|
|
50
|
+
try {
|
|
51
|
+
const cancelled = await params.runner.cancel(
|
|
52
|
+
params.namespace,
|
|
53
|
+
params.agentId,
|
|
54
|
+
PARENT_ABORT_REASON
|
|
55
|
+
);
|
|
56
|
+
await params.context?.onChunk?.({
|
|
57
|
+
type: 'info',
|
|
58
|
+
content: `subagent cancelled by parent abort: ${params.agentId}`,
|
|
59
|
+
data: `subagent cancelled by parent abort: ${params.agentId}`,
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
if (cancelled?.status === 'cancelled' && params.linkedTaskId) {
|
|
63
|
+
await cancelLinkedTaskOnParentAbort({
|
|
64
|
+
namespace: params.namespace,
|
|
65
|
+
linkedTaskId: params.linkedTaskId,
|
|
66
|
+
agentId: params.agentId,
|
|
67
|
+
agentStatus: cancelled.status,
|
|
68
|
+
store: params.store,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
} catch (error) {
|
|
72
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
73
|
+
await params.context?.onChunk?.({
|
|
74
|
+
type: 'stderr',
|
|
75
|
+
content: `failed to cascade parent abort: ${message}`,
|
|
76
|
+
data: `failed to cascade parent abort: ${message}`,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async function cancelLinkedTaskOnParentAbort(params: CancelLinkedTaskParams): Promise<void> {
|
|
82
|
+
await params.store.updateState(params.namespace, (state) => {
|
|
83
|
+
const task = state.tasks[params.linkedTaskId];
|
|
84
|
+
if (!task) {
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
if (task.agentId && task.agentId !== params.agentId) {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
if (task.status === 'completed' || task.status === 'cancelled') {
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const now = Date.now();
|
|
95
|
+
const previousStatus = task.status;
|
|
96
|
+
task.status = 'cancelled';
|
|
97
|
+
task.owner = null;
|
|
98
|
+
task.cancelledAt = now;
|
|
99
|
+
task.updatedAt = now;
|
|
100
|
+
task.version += 1;
|
|
101
|
+
task.history.push({
|
|
102
|
+
timestamp: now,
|
|
103
|
+
action: 'cancelled',
|
|
104
|
+
fromStatus: previousStatus,
|
|
105
|
+
toStatus: 'cancelled',
|
|
106
|
+
actor: 'task-parent-abort',
|
|
107
|
+
reason: PARENT_ABORT_REASON,
|
|
108
|
+
metadata: {
|
|
109
|
+
agentId: params.agentId,
|
|
110
|
+
agentStatus: params.agentStatus,
|
|
111
|
+
},
|
|
112
|
+
});
|
|
113
|
+
return null;
|
|
114
|
+
});
|
|
115
|
+
}
|