@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.
Files changed (209) hide show
  1. package/bin/renx.cjs +16 -0
  2. package/package.json +2 -45
  3. package/src/agent/runtime/runtime.context-usage.test.ts +4 -5
  4. package/src/agent/runtime/runtime.error-handling.test.ts +4 -5
  5. package/src/agent/runtime/runtime.test.ts +7 -4
  6. package/src/agent/runtime/runtime.ts +3 -9
  7. package/src/agent/runtime/runtime.usage-forwarding.test.ts +4 -5
  8. package/src/agent/runtime/source-modules.test.ts +16 -35
  9. package/src/agent/runtime/source-modules.ts +17 -0
  10. package/vendor/agent-root/src/agent/ENTERPRISE_ACCEPTANCE_CHECKLIST.md +95 -0
  11. package/vendor/agent-root/src/agent/ENTERPRISE_REALTIME.html +1345 -0
  12. package/vendor/agent-root/src/agent/ENTERPRISE_REALTIME.md +1353 -0
  13. package/vendor/agent-root/src/agent/ERROR_CONTRACT.md +60 -0
  14. package/vendor/agent-root/src/agent/TEST_COVERAGE_ANALYSIS.md +278 -0
  15. package/vendor/agent-root/src/agent/__test__/error-contract.test.ts +72 -0
  16. package/vendor/agent-root/src/agent/__test__/types.test.ts +137 -0
  17. package/vendor/agent-root/src/agent/agent/__test__/abort-runtime.test.ts +83 -0
  18. package/vendor/agent-root/src/agent/agent/__test__/callback-safety.test.ts +34 -0
  19. package/vendor/agent-root/src/agent/agent/__test__/compaction.test.ts +323 -0
  20. package/vendor/agent-root/src/agent/agent/__test__/concurrency.test.ts +290 -0
  21. package/vendor/agent-root/src/agent/agent/__test__/error-normalizer.test.ts +377 -0
  22. package/vendor/agent-root/src/agent/agent/__test__/error.test.ts +212 -0
  23. package/vendor/agent-root/src/agent/agent/__test__/fault-injection.test.ts +295 -0
  24. package/vendor/agent-root/src/agent/agent/__test__/index.test.ts +3607 -0
  25. package/vendor/agent-root/src/agent/agent/__test__/logger.test.ts +35 -0
  26. package/vendor/agent-root/src/agent/agent/__test__/message-utils.test.ts +517 -0
  27. package/vendor/agent-root/src/agent/agent/__test__/telemetry.test.ts +97 -0
  28. package/vendor/agent-root/src/agent/agent/__test__/timeout-budget.test.ts +479 -0
  29. package/vendor/agent-root/src/agent/agent/__test__/tool-call-merge.test.ts +80 -0
  30. package/vendor/agent-root/src/agent/agent/__test__/tool-execution-ledger.test.ts +76 -0
  31. package/vendor/agent-root/src/agent/agent/__test__/write-buffer.test.ts +173 -0
  32. package/vendor/agent-root/src/agent/agent/__test__/write-file-session.test.ts +109 -0
  33. package/vendor/agent-root/src/agent/agent/abort-runtime.ts +71 -0
  34. package/vendor/agent-root/src/agent/agent/callback-safety.ts +33 -0
  35. package/vendor/agent-root/src/agent/agent/compaction.ts +291 -0
  36. package/vendor/agent-root/src/agent/agent/concurrency.ts +103 -0
  37. package/vendor/agent-root/src/agent/agent/error-normalizer.ts +190 -0
  38. package/vendor/agent-root/src/agent/agent/error.ts +198 -0
  39. package/vendor/agent-root/src/agent/agent/index.ts +1772 -0
  40. package/vendor/agent-root/src/agent/agent/logger.ts +65 -0
  41. package/vendor/agent-root/src/agent/agent/message-utils.ts +101 -0
  42. package/vendor/agent-root/src/agent/agent/stream-events.ts +61 -0
  43. package/vendor/agent-root/src/agent/agent/telemetry.ts +123 -0
  44. package/vendor/agent-root/src/agent/agent/timeout-budget.ts +227 -0
  45. package/vendor/agent-root/src/agent/agent/tool-call-merge.ts +111 -0
  46. package/vendor/agent-root/src/agent/agent/tool-execution-ledger.ts +164 -0
  47. package/vendor/agent-root/src/agent/agent/write-buffer.ts +188 -0
  48. package/vendor/agent-root/src/agent/agent/write-file-session.ts +238 -0
  49. package/vendor/agent-root/src/agent/app/__test__/agent-app-service.test.ts +1053 -0
  50. package/vendor/agent-root/src/agent/app/__test__/minimal-agent-application.test.ts +158 -0
  51. package/vendor/agent-root/src/agent/app/__test__/sqlite-agent-app-store.test.ts +437 -0
  52. package/vendor/agent-root/src/agent/app/agent-app-service.ts +748 -0
  53. package/vendor/agent-root/src/agent/app/contracts.ts +109 -0
  54. package/vendor/agent-root/src/agent/app/index.ts +5 -0
  55. package/vendor/agent-root/src/agent/app/minimal-agent-application.ts +151 -0
  56. package/vendor/agent-root/src/agent/app/ports.ts +72 -0
  57. package/vendor/agent-root/src/agent/app/sqlite-agent-app-store.ts +1182 -0
  58. package/vendor/agent-root/src/agent/app/sqlite-client.ts +177 -0
  59. package/vendor/agent-root/src/agent/docs/cli-app-layer/00-README.md +36 -0
  60. package/vendor/agent-root/src/agent/docs/cli-app-layer/01-scope-and-goals.md +33 -0
  61. package/vendor/agent-root/src/agent/docs/cli-app-layer/02-architecture-overview.md +40 -0
  62. package/vendor/agent-root/src/agent/docs/cli-app-layer/03-domain-model-and-contracts.md +91 -0
  63. package/vendor/agent-root/src/agent/docs/cli-app-layer/04-ports-and-interfaces.md +116 -0
  64. package/vendor/agent-root/src/agent/docs/cli-app-layer/05-run-orchestration-and-state-machine.md +52 -0
  65. package/vendor/agent-root/src/agent/docs/cli-app-layer/06-cli-commands-and-ux.md +53 -0
  66. package/vendor/agent-root/src/agent/docs/cli-app-layer/07-storage-design-local.md +52 -0
  67. package/vendor/agent-root/src/agent/docs/cli-app-layer/08-error-and-observability.md +40 -0
  68. package/vendor/agent-root/src/agent/docs/cli-app-layer/09-security-and-policy-boundary.md +19 -0
  69. package/vendor/agent-root/src/agent/docs/cli-app-layer/10-test-plan-and-acceptance.md +28 -0
  70. package/vendor/agent-root/src/agent/docs/cli-app-layer/11-implementation-phases.md +26 -0
  71. package/vendor/agent-root/src/agent/docs/cli-app-layer/12-open-questions-and-risks.md +30 -0
  72. package/vendor/agent-root/src/agent/docs/cli-app-layer/13-sqlite-schema-fields-and-rationale.md +567 -0
  73. package/vendor/agent-root/src/agent/docs/cli-app-layer/14-project-flow-mermaid.md +583 -0
  74. package/vendor/agent-root/src/agent/docs/cli-app-layer/15-openclaw-style-project-blueprint.md +972 -0
  75. package/vendor/agent-root/src/agent/error-contract.ts +154 -0
  76. package/vendor/agent-root/src/agent/prompts/system.ts +246 -0
  77. package/vendor/agent-root/src/agent/prompts/system1.ts +208 -0
  78. package/vendor/agent-root/src/agent/storage/__test__/file-history-store.test.ts +98 -0
  79. package/vendor/agent-root/src/agent/storage/file-history-store.ts +313 -0
  80. package/vendor/agent-root/src/agent/storage/file-storage-config.ts +94 -0
  81. package/vendor/agent-root/src/agent/storage/file-system.ts +31 -0
  82. package/vendor/agent-root/src/agent/storage/file-write-service.ts +21 -0
  83. package/vendor/agent-root/src/agent/tool/__test__/base-tool.test.ts +413 -0
  84. package/vendor/agent-root/src/agent/tool/__test__/bash-policy.test.ts +356 -0
  85. package/vendor/agent-root/src/agent/tool/__test__/bash.mocked-coverage.test.ts +375 -0
  86. package/vendor/agent-root/src/agent/tool/__test__/bash.test.ts +372 -0
  87. package/vendor/agent-root/src/agent/tool/__test__/error.test.ts +108 -0
  88. package/vendor/agent-root/src/agent/tool/__test__/file-edit-tool.test.ts +258 -0
  89. package/vendor/agent-root/src/agent/tool/__test__/file-history-tools.test.ts +121 -0
  90. package/vendor/agent-root/src/agent/tool/__test__/file-read-tool.test.ts +210 -0
  91. package/vendor/agent-root/src/agent/tool/__test__/glob.test.ts +139 -0
  92. package/vendor/agent-root/src/agent/tool/__test__/grep.mocked-coverage.test.ts +456 -0
  93. package/vendor/agent-root/src/agent/tool/__test__/grep.test.ts +192 -0
  94. package/vendor/agent-root/src/agent/tool/__test__/lsp.test.ts +300 -0
  95. package/vendor/agent-root/src/agent/tool/__test__/outside-workspace-confirmation.test.ts +214 -0
  96. package/vendor/agent-root/src/agent/tool/__test__/path-security.test.ts +336 -0
  97. package/vendor/agent-root/src/agent/tool/__test__/skill-loader.test.ts +494 -0
  98. package/vendor/agent-root/src/agent/tool/__test__/skill-parser.test.ts +543 -0
  99. package/vendor/agent-root/src/agent/tool/__test__/skill-tool.test.ts +172 -0
  100. package/vendor/agent-root/src/agent/tool/__test__/task-concurrency-and-version.test.ts +116 -0
  101. package/vendor/agent-root/src/agent/tool/__test__/task-create-get-list-update.test.ts +267 -0
  102. package/vendor/agent-root/src/agent/tool/__test__/task-create.test.ts +519 -0
  103. package/vendor/agent-root/src/agent/tool/__test__/task-errors.test.ts +225 -0
  104. package/vendor/agent-root/src/agent/tool/__test__/task-output-blocking.test.ts +223 -0
  105. package/vendor/agent-root/src/agent/tool/__test__/task-output.test.ts +184 -0
  106. package/vendor/agent-root/src/agent/tool/__test__/task-parent-abort.test.ts +287 -0
  107. package/vendor/agent-root/src/agent/tool/__test__/task-real-runner-adapter.test.ts +190 -0
  108. package/vendor/agent-root/src/agent/tool/__test__/task-run-lifecycle.test.ts +352 -0
  109. package/vendor/agent-root/src/agent/tool/__test__/task-store-runner-branches.test.ts +395 -0
  110. package/vendor/agent-root/src/agent/tool/__test__/task-store.test.ts +391 -0
  111. package/vendor/agent-root/src/agent/tool/__test__/task-subagent-config-integration.test.ts +176 -0
  112. package/vendor/agent-root/src/agent/tool/__test__/task-subagent-config.test.ts +68 -0
  113. package/vendor/agent-root/src/agent/tool/__test__/task-tools-core-edges.test.ts +630 -0
  114. package/vendor/agent-root/src/agent/tool/__test__/task-tools-runtime-edges.test.ts +732 -0
  115. package/vendor/agent-root/src/agent/tool/__test__/task-types.test.ts +494 -0
  116. package/vendor/agent-root/src/agent/tool/__test__/task-utils-branches.test.ts +175 -0
  117. package/vendor/agent-root/src/agent/tool/__test__/tool-manager.test.ts +505 -0
  118. package/vendor/agent-root/src/agent/tool/__test__/types.test.ts +55 -0
  119. package/vendor/agent-root/src/agent/tool/__test__/web-fetch.test.ts +244 -0
  120. package/vendor/agent-root/src/agent/tool/__test__/web-search.test.ts +290 -0
  121. package/vendor/agent-root/src/agent/tool/__test__/write-file.test.ts +368 -0
  122. package/vendor/agent-root/src/agent/tool/base-tool.ts +345 -0
  123. package/vendor/agent-root/src/agent/tool/bash-policy.ts +636 -0
  124. package/vendor/agent-root/src/agent/tool/bash.ts +688 -0
  125. package/vendor/agent-root/src/agent/tool/error.ts +131 -0
  126. package/vendor/agent-root/src/agent/tool/file-edit-tool.ts +264 -0
  127. package/vendor/agent-root/src/agent/tool/file-history-list.ts +103 -0
  128. package/vendor/agent-root/src/agent/tool/file-history-restore.ts +149 -0
  129. package/vendor/agent-root/src/agent/tool/file-read-tool.ts +211 -0
  130. package/vendor/agent-root/src/agent/tool/glob.ts +171 -0
  131. package/vendor/agent-root/src/agent/tool/grep.ts +496 -0
  132. package/vendor/agent-root/src/agent/tool/lsp.ts +481 -0
  133. package/vendor/agent-root/src/agent/tool/path-security.ts +117 -0
  134. package/vendor/agent-root/src/agent/tool/search/common.ts +153 -0
  135. package/vendor/agent-root/src/agent/tool/skill/index.ts +13 -0
  136. package/vendor/agent-root/src/agent/tool/skill/loader.ts +229 -0
  137. package/vendor/agent-root/src/agent/tool/skill/parser.ts +124 -0
  138. package/vendor/agent-root/src/agent/tool/skill/types.ts +27 -0
  139. package/vendor/agent-root/src/agent/tool/skill-tool.ts +143 -0
  140. package/vendor/agent-root/src/agent/tool/task-create.ts +186 -0
  141. package/vendor/agent-root/src/agent/tool/task-errors.ts +42 -0
  142. package/vendor/agent-root/src/agent/tool/task-get.ts +116 -0
  143. package/vendor/agent-root/src/agent/tool/task-graph.ts +78 -0
  144. package/vendor/agent-root/src/agent/tool/task-list.ts +141 -0
  145. package/vendor/agent-root/src/agent/tool/task-mock-runner-adapter.ts +232 -0
  146. package/vendor/agent-root/src/agent/tool/task-output.ts +223 -0
  147. package/vendor/agent-root/src/agent/tool/task-parent-abort.ts +115 -0
  148. package/vendor/agent-root/src/agent/tool/task-real-runner-adapter.ts +336 -0
  149. package/vendor/agent-root/src/agent/tool/task-runner-adapter.ts +55 -0
  150. package/vendor/agent-root/src/agent/tool/task-stop.ts +187 -0
  151. package/vendor/agent-root/src/agent/tool/task-store.ts +217 -0
  152. package/vendor/agent-root/src/agent/tool/task-subagent-config.ts +149 -0
  153. package/vendor/agent-root/src/agent/tool/task-types.ts +264 -0
  154. package/vendor/agent-root/src/agent/tool/task-update.ts +315 -0
  155. package/vendor/agent-root/src/agent/tool/task.ts +209 -0
  156. package/vendor/agent-root/src/agent/tool/tool-manager.ts +362 -0
  157. package/vendor/agent-root/src/agent/tool/tool-prompts.ts +242 -0
  158. package/vendor/agent-root/src/agent/tool/types.ts +116 -0
  159. package/vendor/agent-root/src/agent/tool/web-fetch.ts +227 -0
  160. package/vendor/agent-root/src/agent/tool/web-search.ts +208 -0
  161. package/vendor/agent-root/src/agent/tool/write-file.ts +497 -0
  162. package/vendor/agent-root/src/agent/types.ts +232 -0
  163. package/vendor/agent-root/src/agent/utils/__tests__/index.test.ts +18 -0
  164. package/vendor/agent-root/src/agent/utils/__tests__/message-utils.test.ts +610 -0
  165. package/vendor/agent-root/src/agent/utils/__tests__/message.test.ts +223 -0
  166. package/vendor/agent-root/src/agent/utils/__tests__/token.test.ts +42 -0
  167. package/vendor/agent-root/src/agent/utils/index.ts +16 -0
  168. package/vendor/agent-root/src/agent/utils/message.ts +171 -0
  169. package/vendor/agent-root/src/agent/utils/token.ts +28 -0
  170. package/vendor/agent-root/src/config/__tests__/load-config-to-env.test.ts +129 -0
  171. package/vendor/agent-root/src/config/__tests__/loader.test.ts +247 -0
  172. package/vendor/agent-root/src/config/__tests__/runtime.test.ts +88 -0
  173. package/vendor/agent-root/src/config/index.ts +54 -0
  174. package/vendor/agent-root/src/config/loader.ts +431 -0
  175. package/vendor/agent-root/src/config/paths.ts +30 -0
  176. package/vendor/agent-root/src/config/runtime.ts +163 -0
  177. package/vendor/agent-root/src/config/types.ts +70 -0
  178. package/vendor/agent-root/src/logger/index.ts +57 -0
  179. package/vendor/agent-root/src/logger/logger.ts +819 -0
  180. package/vendor/agent-root/src/logger/types.ts +150 -0
  181. package/vendor/agent-root/src/providers/__tests__/errors.test.ts +441 -0
  182. package/vendor/agent-root/src/providers/__tests__/index.test.ts +16 -0
  183. package/vendor/agent-root/src/providers/__tests__/openai-compatible.options.test.ts +318 -0
  184. package/vendor/agent-root/src/providers/__tests__/openai-compatible.test.ts +600 -0
  185. package/vendor/agent-root/src/providers/__tests__/registry.test.ts +449 -0
  186. package/vendor/agent-root/src/providers/__tests__/responses-adapter.test.ts +298 -0
  187. package/vendor/agent-root/src/providers/adapters/__tests__/anthropic.test.ts +354 -0
  188. package/vendor/agent-root/src/providers/adapters/__tests__/kimi.test.ts +58 -0
  189. package/vendor/agent-root/src/providers/adapters/__tests__/standard.test.ts +261 -0
  190. package/vendor/agent-root/src/providers/adapters/anthropic.ts +572 -0
  191. package/vendor/agent-root/src/providers/adapters/base.ts +131 -0
  192. package/vendor/agent-root/src/providers/adapters/kimi.ts +48 -0
  193. package/vendor/agent-root/src/providers/adapters/responses.ts +732 -0
  194. package/vendor/agent-root/src/providers/adapters/standard.ts +120 -0
  195. package/vendor/agent-root/src/providers/http/__tests__/client.timeout.test.ts +313 -0
  196. package/vendor/agent-root/src/providers/http/client.ts +289 -0
  197. package/vendor/agent-root/src/providers/http/stream-parser.ts +109 -0
  198. package/vendor/agent-root/src/providers/index.ts +76 -0
  199. package/vendor/agent-root/src/providers/kimi-headers.ts +177 -0
  200. package/vendor/agent-root/src/providers/openai-compatible.ts +387 -0
  201. package/vendor/agent-root/src/providers/registry/model-config.ts +230 -0
  202. package/vendor/agent-root/src/providers/registry/provider-factory.ts +123 -0
  203. package/vendor/agent-root/src/providers/registry.ts +135 -0
  204. package/vendor/agent-root/src/providers/types/api.ts +284 -0
  205. package/vendor/agent-root/src/providers/types/config.ts +58 -0
  206. package/vendor/agent-root/src/providers/types/errors.ts +323 -0
  207. package/vendor/agent-root/src/providers/types/index.ts +72 -0
  208. package/vendor/agent-root/src/providers/types/provider.ts +45 -0
  209. package/vendor/agent-root/src/providers/types/registry.ts +88 -0
@@ -0,0 +1,336 @@
1
+ import type { Tool as ProviderTool } from '../../providers';
2
+ import type { RunRecord } from '../app/contracts';
3
+ import type {
4
+ RunForegroundCallbacks,
5
+ RunForegroundRequest,
6
+ RunForegroundResult,
7
+ } from '../app/agent-app-service';
8
+ import type { Message } from '../types';
9
+ import type { TaskStore } from './task-store';
10
+ import {
11
+ createAgentId,
12
+ safeJsonClone,
13
+ type AgentRunEntity,
14
+ type AgentRunStatus,
15
+ } from './task-types';
16
+ import type { StartAgentInput, SubagentRunnerAdapter } from './task-runner-adapter';
17
+ import type { ToolExecutionContext } from './types';
18
+
19
+ interface SubagentExecutionService {
20
+ runForeground(
21
+ request: RunForegroundRequest,
22
+ callbacks?: RunForegroundCallbacks
23
+ ): Promise<RunForegroundResult>;
24
+ getRun(executionId: string): Promise<RunRecord | null>;
25
+ listContextMessages(conversationId: string): Promise<Message[]>;
26
+ }
27
+
28
+ interface LiveRunState {
29
+ abortController: AbortController;
30
+ }
31
+
32
+ interface RunLocator {
33
+ executionId: string;
34
+ conversationId: string;
35
+ }
36
+
37
+ export interface RealSubagentRunnerAdapterOptions {
38
+ store: TaskStore;
39
+ appService: SubagentExecutionService;
40
+ resolveTools?: (allowedTools?: string[]) => ProviderTool[] | undefined;
41
+ resolveModelId?: (model?: StartAgentInput['model']) => string | undefined;
42
+ now?: () => number;
43
+ }
44
+
45
+ export class RealSubagentRunnerAdapter implements SubagentRunnerAdapter {
46
+ private readonly store: TaskStore;
47
+ private readonly appService: SubagentExecutionService;
48
+ private readonly resolveTools?: (allowedTools?: string[]) => ProviderTool[] | undefined;
49
+ private readonly resolveModelId?: (model?: StartAgentInput['model']) => string | undefined;
50
+ private readonly now: () => number;
51
+ private readonly liveRuns = new Map<string, LiveRunState>();
52
+
53
+ constructor(options: RealSubagentRunnerAdapterOptions) {
54
+ this.store = options.store;
55
+ this.appService = options.appService;
56
+ this.resolveTools = options.resolveTools;
57
+ this.resolveModelId = options.resolveModelId;
58
+ this.now = options.now || Date.now;
59
+ }
60
+
61
+ async start(
62
+ namespace: string,
63
+ input: StartAgentInput,
64
+ context?: ToolExecutionContext
65
+ ): Promise<AgentRunEntity> {
66
+ if (input.resume) {
67
+ const resumed = await this.poll(namespace, input.resume);
68
+ if (!resumed) {
69
+ throw new Error(`AGENT_RUN_NOT_FOUND: ${input.resume}`);
70
+ }
71
+ return resumed;
72
+ }
73
+
74
+ const now = this.now();
75
+ const agentId = createAgentId();
76
+ const locator = this.createLocator(namespace, agentId);
77
+ const initial: AgentRunEntity = {
78
+ agentId,
79
+ status: 'running',
80
+ subagentType: input.subagentType,
81
+ prompt: input.prompt,
82
+ description: input.description,
83
+ model: input.model,
84
+ maxTurns: input.maxTurns,
85
+ allowedTools: input.allowedTools,
86
+ linkedTaskId: input.linkedTaskId,
87
+ createdAt: now,
88
+ startedAt: now,
89
+ updatedAt: now,
90
+ progress: 0,
91
+ metadata: {
92
+ ...(input.metadata || {}),
93
+ ...(input.systemPrompt ? { systemPrompt: input.systemPrompt } : {}),
94
+ executionId: locator.executionId,
95
+ conversationId: locator.conversationId,
96
+ },
97
+ version: 1,
98
+ };
99
+
100
+ const projected = await this.upsertProjection(namespace, initial);
101
+ await context?.onChunk?.({
102
+ type: 'info',
103
+ content: `subagent started: ${agentId}`,
104
+ data: `subagent started: ${agentId}`,
105
+ });
106
+
107
+ const liveKey = this.liveKey(namespace, agentId);
108
+ const live = { abortController: new AbortController() };
109
+ this.liveRuns.set(liveKey, live);
110
+
111
+ const runPromise = this.runExecution(namespace, projected, input, live, context);
112
+ if (input.runInBackground) {
113
+ void runPromise;
114
+ return projected;
115
+ }
116
+ return runPromise;
117
+ }
118
+
119
+ async poll(namespace: string, agentId: string): Promise<AgentRunEntity | null> {
120
+ const state = await this.store.getState(namespace);
121
+ const current = state.agentRuns[agentId];
122
+ if (!current) {
123
+ return null;
124
+ }
125
+
126
+ const locator = this.readLocator(current);
127
+ const remote = await this.appService.getRun(locator.executionId);
128
+ if (!remote) {
129
+ return safeJsonClone(current);
130
+ }
131
+ if (
132
+ current.status === 'cancelled' &&
133
+ (remote.status === 'CREATED' || remote.status === 'QUEUED' || remote.status === 'RUNNING')
134
+ ) {
135
+ return safeJsonClone(current);
136
+ }
137
+
138
+ const mapped = this.mapRunRecord(current, remote);
139
+ if (mapped.status === 'completed' && (!mapped.output || mapped.output.trim().length === 0)) {
140
+ mapped.output = await this.readCompletionOutput(locator.conversationId);
141
+ }
142
+
143
+ return this.upsertProjection(namespace, mapped);
144
+ }
145
+
146
+ async cancel(
147
+ namespace: string,
148
+ agentId: string,
149
+ reason?: string
150
+ ): Promise<AgentRunEntity | null> {
151
+ const key = this.liveKey(namespace, agentId);
152
+ const live = this.liveRuns.get(key);
153
+ if (!live) {
154
+ const existing = await this.poll(namespace, agentId);
155
+ if (!existing || this.isActive(existing.status)) {
156
+ return null;
157
+ }
158
+ return existing;
159
+ }
160
+
161
+ live.abortController.abort(reason || 'Cancelled by task_stop');
162
+ const state = await this.store.getState(namespace);
163
+ const current = state.agentRuns[agentId];
164
+ if (!current) {
165
+ return null;
166
+ }
167
+
168
+ const cancelled: AgentRunEntity = {
169
+ ...safeJsonClone(current),
170
+ status: 'cancelled',
171
+ progress: current.progress || 0,
172
+ error: reason || 'Cancelled by task_stop',
173
+ endedAt: this.now(),
174
+ updatedAt: this.now(),
175
+ };
176
+ return this.upsertProjection(namespace, cancelled);
177
+ }
178
+
179
+ private async runExecution(
180
+ namespace: string,
181
+ initial: AgentRunEntity,
182
+ input: StartAgentInput,
183
+ live: LiveRunState,
184
+ _context?: ToolExecutionContext
185
+ ): Promise<AgentRunEntity> {
186
+ const locator = this.readLocator(initial);
187
+ const request: RunForegroundRequest = {
188
+ conversationId: locator.conversationId,
189
+ executionId: locator.executionId,
190
+ userInput: input.prompt,
191
+ systemPrompt: input.systemPrompt,
192
+ maxSteps: input.maxTurns,
193
+ tools: this.resolveTools?.(input.allowedTools),
194
+ abortSignal: live.abortController.signal,
195
+ config: this.buildConfig(input.model),
196
+ };
197
+
198
+ try {
199
+ const result = await this.appService.runForeground(request);
200
+ const output = extractAssistantText(result.messages);
201
+ const mapped = this.mapRunRecord(initial, result.run, output);
202
+ return await this.upsertProjection(namespace, mapped);
203
+ } catch (error) {
204
+ const aborted = live.abortController.signal.aborted;
205
+ const message = error instanceof Error ? error.message : String(error);
206
+ const failed: AgentRunEntity = {
207
+ ...safeJsonClone(initial),
208
+ status: aborted ? 'cancelled' : 'failed',
209
+ error: message,
210
+ progress: aborted ? initial.progress || 0 : initial.progress || 0,
211
+ endedAt: this.now(),
212
+ updatedAt: this.now(),
213
+ };
214
+ return await this.upsertProjection(namespace, failed);
215
+ } finally {
216
+ this.liveRuns.delete(this.liveKey(namespace, initial.agentId));
217
+ }
218
+ }
219
+
220
+ private mapRunRecord(base: AgentRunEntity, run: RunRecord, output?: string): AgentRunEntity {
221
+ const status = mapStatus(run);
222
+ const terminalError = status === 'failed' || status === 'timed_out' || status === 'cancelled';
223
+ return {
224
+ ...safeJsonClone(base),
225
+ status,
226
+ progress: status === 'completed' ? 100 : base.progress || 0,
227
+ output: status === 'completed' ? output : undefined,
228
+ error: terminalError ? run.errorMessage || base.error : undefined,
229
+ startedAt: run.startedAt || base.startedAt,
230
+ endedAt: run.completedAt || base.endedAt,
231
+ updatedAt: run.updatedAt || this.now(),
232
+ metadata: {
233
+ ...(base.metadata || {}),
234
+ terminalReason: run.terminalReason,
235
+ },
236
+ };
237
+ }
238
+
239
+ private async upsertProjection(namespace: string, next: AgentRunEntity): Promise<AgentRunEntity> {
240
+ const result = await this.store.updateState(namespace, (state) => {
241
+ const existing = state.agentRuns[next.agentId];
242
+ const mergedMetadata = {
243
+ ...(existing?.metadata || {}),
244
+ ...(next.metadata || {}),
245
+ };
246
+ const merged: AgentRunEntity = {
247
+ ...(existing ? safeJsonClone(existing) : {}),
248
+ ...safeJsonClone(next),
249
+ metadata: mergedMetadata,
250
+ version: existing ? existing.version + 1 : 1,
251
+ };
252
+ state.agentRuns[next.agentId] = safeJsonClone(merged);
253
+ return safeJsonClone(merged);
254
+ });
255
+ return result.result;
256
+ }
257
+
258
+ private createLocator(namespace: string, agentId: string): RunLocator {
259
+ return {
260
+ executionId: agentId,
261
+ conversationId: `taskns:${namespace}:agent:${agentId}`,
262
+ };
263
+ }
264
+
265
+ private readLocator(run: AgentRunEntity): RunLocator {
266
+ const metadata = run.metadata || {};
267
+ const executionId =
268
+ typeof metadata.executionId === 'string' ? metadata.executionId : run.agentId;
269
+ const conversationId =
270
+ typeof metadata.conversationId === 'string'
271
+ ? metadata.conversationId
272
+ : `taskns:default:agent:${run.agentId}`;
273
+ return { executionId, conversationId };
274
+ }
275
+
276
+ private async readCompletionOutput(conversationId: string): Promise<string | undefined> {
277
+ try {
278
+ const messages = await this.appService.listContextMessages(conversationId);
279
+ return extractAssistantText(messages);
280
+ } catch {
281
+ return undefined;
282
+ }
283
+ }
284
+
285
+ private buildConfig(modelHint?: StartAgentInput['model']): { model?: string } | undefined {
286
+ const model = this.resolveModelId?.(modelHint);
287
+ return model ? { model } : undefined;
288
+ }
289
+
290
+ private liveKey(namespace: string, agentId: string): string {
291
+ return `${namespace}::${agentId}`;
292
+ }
293
+
294
+ private isActive(status: AgentRunStatus): boolean {
295
+ return status === 'queued' || status === 'running' || status === 'paused';
296
+ }
297
+ }
298
+
299
+ function mapStatus(run: RunRecord): AgentRunStatus {
300
+ switch (run.status) {
301
+ case 'CREATED':
302
+ case 'QUEUED':
303
+ return 'queued';
304
+ case 'RUNNING':
305
+ return 'running';
306
+ case 'COMPLETED':
307
+ return 'completed';
308
+ case 'CANCELLED':
309
+ return 'cancelled';
310
+ case 'FAILED':
311
+ return run.terminalReason === 'timeout' ? 'timed_out' : 'failed';
312
+ default:
313
+ return 'failed';
314
+ }
315
+ }
316
+
317
+ function extractAssistantText(messages: Message[]): string | undefined {
318
+ for (let index = messages.length - 1; index >= 0; index -= 1) {
319
+ const message = messages[index];
320
+ if (message.role !== 'assistant') {
321
+ continue;
322
+ }
323
+ if (typeof message.content === 'string') {
324
+ const text = message.content.trim();
325
+ if (text.length > 0) {
326
+ return text;
327
+ }
328
+ continue;
329
+ }
330
+ const serialized = JSON.stringify(message.content);
331
+ if (serialized.length > 0) {
332
+ return serialized;
333
+ }
334
+ }
335
+ return undefined;
336
+ }
@@ -0,0 +1,55 @@
1
+ import type { ToolExecutionContext } from './types';
2
+ import type { AgentRunEntity, SubagentType } from './task-types';
3
+
4
+ export interface StartAgentInput {
5
+ subagentType: SubagentType;
6
+ prompt: string;
7
+ systemPrompt?: string;
8
+ description?: string;
9
+ model?: 'sonnet' | 'opus' | 'haiku';
10
+ maxTurns?: number;
11
+ allowedTools?: string[];
12
+ runInBackground?: boolean;
13
+ resume?: string;
14
+ linkedTaskId?: string;
15
+ metadata?: Record<string, unknown>;
16
+ }
17
+
18
+ export interface SubagentRunnerAdapter {
19
+ start(
20
+ namespace: string,
21
+ input: StartAgentInput,
22
+ context?: ToolExecutionContext
23
+ ): Promise<AgentRunEntity>;
24
+ poll(namespace: string, agentId: string): Promise<AgentRunEntity | null>;
25
+ cancel(namespace: string, agentId: string, reason?: string): Promise<AgentRunEntity | null>;
26
+ }
27
+
28
+ class UnconfiguredSubagentRunnerAdapter implements SubagentRunnerAdapter {
29
+ async start(): Promise<AgentRunEntity> {
30
+ throw new Error(
31
+ 'TASK_RUNNER_NOT_CONFIGURED: real subagent runner is required. Inject runner from runtime.'
32
+ );
33
+ }
34
+
35
+ async poll(): Promise<AgentRunEntity | null> {
36
+ return null;
37
+ }
38
+
39
+ async cancel(): Promise<AgentRunEntity | null> {
40
+ return null;
41
+ }
42
+ }
43
+
44
+ export function createUnconfiguredSubagentRunnerAdapter(): SubagentRunnerAdapter {
45
+ return new UnconfiguredSubagentRunnerAdapter();
46
+ }
47
+
48
+ export {
49
+ InProcessMockRunnerAdapter,
50
+ type InProcessMockRunnerAdapterOptions,
51
+ } from './task-mock-runner-adapter';
52
+ export {
53
+ RealSubagentRunnerAdapter,
54
+ type RealSubagentRunnerAdapterOptions,
55
+ } from './task-real-runner-adapter';
@@ -0,0 +1,187 @@
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 } from './task-types';
10
+ import { TASK_STOP_DESCRIPTION } from './tool-prompts';
11
+
12
+ const cancelLinkedTaskSchema = z.preprocess((value) => {
13
+ if (typeof value === 'string') {
14
+ const normalized = value.trim().toLowerCase();
15
+ if (normalized === 'true') return true;
16
+ if (normalized === 'false') return false;
17
+ }
18
+ return value;
19
+ }, z.boolean());
20
+
21
+ const schema = z
22
+ .object({
23
+ namespace: z.string().min(1).optional().describe('Optional task namespace'),
24
+ agent_id: z.string().min(1).optional().describe('Direct agent run id to stop'),
25
+ task_id: z
26
+ .string()
27
+ .min(1)
28
+ .optional()
29
+ .describe('Planning task id used to resolve linked agent run'),
30
+ reason: z.string().optional().describe('Optional cancellation reason'),
31
+ cancel_linked_task: cancelLinkedTaskSchema
32
+ .optional()
33
+ .describe('When true, also cancel linked planning tasks'),
34
+ })
35
+ .strict();
36
+
37
+ type TaskStopArgs = z.infer<typeof schema>;
38
+
39
+ export interface TaskStopToolOptions {
40
+ store?: TaskStore;
41
+ runner?: SubagentRunnerAdapter;
42
+ defaultNamespace?: string;
43
+ }
44
+
45
+ export class TaskStopTool extends BaseTool<typeof schema> {
46
+ name = 'task_stop';
47
+ description = TASK_STOP_DESCRIPTION;
48
+ parameters = schema;
49
+
50
+ private readonly store: TaskStore;
51
+ private readonly runner: SubagentRunnerAdapter;
52
+ private readonly defaultNamespace?: string;
53
+
54
+ constructor(options: TaskStopToolOptions = {}) {
55
+ super();
56
+ this.store = options.store || getTaskStore();
57
+ this.runner = options.runner || createUnconfiguredSubagentRunnerAdapter();
58
+ this.defaultNamespace = options.defaultNamespace;
59
+ }
60
+
61
+ override getConcurrencyMode(): 'exclusive' {
62
+ return 'exclusive';
63
+ }
64
+
65
+ override getConcurrencyLockKey(args: TaskStopArgs): string {
66
+ const namespace = args.namespace || this.defaultNamespace || 'default';
67
+ return `taskns:${namespace}`;
68
+ }
69
+
70
+ async execute(args: TaskStopArgs): Promise<ToolResult> {
71
+ const namespace = args.namespace || this.defaultNamespace;
72
+ const normalizedNamespace = this.store.normalizeNamespace(namespace);
73
+
74
+ const resolved = await this.resolveAgentId(normalizedNamespace, args);
75
+ if (!resolved.ok) {
76
+ return buildTaskFailure(resolved.code, resolved.message, {
77
+ namespace: normalizedNamespace,
78
+ });
79
+ }
80
+
81
+ const agentId = resolved.agentId;
82
+ const before = await this.runner.poll(normalizedNamespace, agentId);
83
+ if (!before) {
84
+ return buildTaskFailure('AGENT_RUN_NOT_FOUND', `agent run not found: ${agentId}`, {
85
+ namespace: normalizedNamespace,
86
+ });
87
+ }
88
+ if (isAgentRunTerminal(before.status)) {
89
+ return buildTaskFailure(
90
+ 'AGENT_RUN_ALREADY_TERMINAL',
91
+ `agent run already terminal: ${before.status}`,
92
+ {
93
+ namespace: normalizedNamespace,
94
+ agent_id: agentId,
95
+ }
96
+ );
97
+ }
98
+
99
+ const cancelled = await this.runner.cancel(normalizedNamespace, agentId, args.reason);
100
+ if (!cancelled) {
101
+ return buildTaskFailure('AGENT_RUN_NOT_FOUND', `agent run not found: ${agentId}`, {
102
+ namespace: normalizedNamespace,
103
+ });
104
+ }
105
+
106
+ const affectedTaskIds: string[] = [];
107
+ const cancelLinkedTask = args.cancel_linked_task !== undefined ? args.cancel_linked_task : true;
108
+
109
+ if (cancelLinkedTask) {
110
+ const updated = await this.store.updateState(normalizedNamespace, (state) => {
111
+ const now = Date.now();
112
+ const targets = Object.values(state.tasks).filter((task) => task.agentId === agentId);
113
+
114
+ for (const task of targets) {
115
+ if (task.status === 'completed' || task.status === 'cancelled') {
116
+ continue;
117
+ }
118
+ const previousStatus = task.status;
119
+ task.status = 'cancelled';
120
+ task.owner = null;
121
+ task.cancelledAt = now;
122
+ task.updatedAt = now;
123
+ task.version += 1;
124
+ task.history.push({
125
+ timestamp: now,
126
+ action: 'cancelled',
127
+ fromStatus: previousStatus,
128
+ toStatus: 'cancelled',
129
+ actor: 'task_stop',
130
+ reason: args.reason || 'Cancelled by task_stop',
131
+ metadata: {
132
+ agentId,
133
+ },
134
+ });
135
+ affectedTaskIds.push(task.id);
136
+ }
137
+ return null;
138
+ });
139
+ void updated;
140
+ }
141
+
142
+ return buildTaskSuccess({
143
+ namespace: normalizedNamespace,
144
+ agent_run: safeJsonClone(cancelled),
145
+ cancelled_task_ids: affectedTaskIds,
146
+ });
147
+ }
148
+
149
+ private async resolveAgentId(
150
+ namespace: string,
151
+ args: TaskStopArgs
152
+ ): Promise<{ ok: true; agentId: string } | { ok: false; code: string; message: string }> {
153
+ if (args.agent_id) {
154
+ return { ok: true, agentId: args.agent_id };
155
+ }
156
+ if (!args.task_id) {
157
+ return {
158
+ ok: false,
159
+ code: 'TASK_STOP_TARGET_REQUIRED',
160
+ message: 'agent_id or task_id is required',
161
+ };
162
+ }
163
+
164
+ const state = await this.store.getState(namespace);
165
+ const task = state.tasks[args.task_id];
166
+ if (!task) {
167
+ return {
168
+ ok: false,
169
+ code: 'TASK_NOT_FOUND',
170
+ message: `task not found: ${args.task_id}`,
171
+ };
172
+ }
173
+ if (!task.agentId) {
174
+ return {
175
+ ok: false,
176
+ code: 'AGENT_RUN_NOT_FOUND',
177
+ message: `task has no linked agent run: ${args.task_id}`,
178
+ };
179
+ }
180
+ return {
181
+ ok: true,
182
+ agentId: task.agentId,
183
+ };
184
+ }
185
+ }
186
+
187
+ export default TaskStopTool;