@botlearn-course/daemon 0.0.13 → 0.0.15
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/README.md +5 -2
- package/dist/agent-service-sandbox.d.ts +15 -0
- package/dist/agent-service-sandbox.js +227 -21
- package/dist/agent-service-ws-protocol.d.ts +1 -1
- package/dist/agent-service-ws-protocol.js +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/log.d.ts +9 -0
- package/dist/log.js +24 -2
- package/dist/mcp/course-skills-relay.d.ts +2 -0
- package/dist/mcp/course-skills-relay.js +54 -0
- package/dist/mcp/course-skills-server.d.ts +49 -0
- package/dist/mcp/course-skills-server.js +439 -0
- package/dist/run-dispatcher.d.ts +2 -0
- package/dist/run-dispatcher.js +61 -2
- package/dist/runtime-capabilities.d.ts +1 -0
- package/dist/runtime-capabilities.js +4 -0
- package/dist/runtime-skills.d.ts +93 -0
- package/dist/runtime-skills.js +401 -0
- package/dist/runtimes/deepseek-tui.d.ts +2 -1
- package/dist/runtimes/deepseek-tui.js +252 -25
- package/dist/runtimes/engine.d.ts +6 -0
- package/dist/runtimes/engine.js +6 -1
- package/dist/runtimes/progress.d.ts +2 -0
- package/dist/runtimes/progress.js +34 -0
- package/dist/tool-observation.d.ts +21 -0
- package/dist/tool-observation.js +120 -0
- package/dist/types.d.ts +26 -2
- package/package.json +1 -1
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { REDACTED, redactSecretsDeep, } from "./redaction.js";
|
|
3
|
+
export const AGENT_TOOL_OBSERVATION_SCHEMA_VERSION = "agent-tool-observation/0.1";
|
|
4
|
+
const DETAIL_MAX_CHARS = 4_000;
|
|
5
|
+
const MAX_PROJECT_DEPTH = 8;
|
|
6
|
+
const SAFE_TOOL_NAME = /^[A-Za-z0-9][A-Za-z0-9._:/-]{0,79}$/;
|
|
7
|
+
const CALL_FIELDS = new Set([
|
|
8
|
+
"arguments",
|
|
9
|
+
"args",
|
|
10
|
+
"input",
|
|
11
|
+
"command",
|
|
12
|
+
"cmd",
|
|
13
|
+
"cwd",
|
|
14
|
+
"path",
|
|
15
|
+
"file_path",
|
|
16
|
+
"query",
|
|
17
|
+
"url",
|
|
18
|
+
"pattern",
|
|
19
|
+
"patch",
|
|
20
|
+
"changes",
|
|
21
|
+
"edits",
|
|
22
|
+
]);
|
|
23
|
+
const RESULT_FIELDS = new Set([
|
|
24
|
+
"result",
|
|
25
|
+
"output",
|
|
26
|
+
"stdout",
|
|
27
|
+
"stderr",
|
|
28
|
+
"exit_code",
|
|
29
|
+
"status",
|
|
30
|
+
"status_code",
|
|
31
|
+
"error",
|
|
32
|
+
"diff",
|
|
33
|
+
"path",
|
|
34
|
+
"file_path",
|
|
35
|
+
"bytes",
|
|
36
|
+
]);
|
|
37
|
+
/**
|
|
38
|
+
* Project a provider tool envelope into durable teacher evidence.
|
|
39
|
+
*
|
|
40
|
+
* The projection is deliberately lossy: only operational argument/result fields survive,
|
|
41
|
+
* credentials are removed, host paths become workspace-relative, and the JSON preview is
|
|
42
|
+
* bounded. Provider reasoning, message text, request IDs, and arbitrary envelope metadata
|
|
43
|
+
* never cross this boundary.
|
|
44
|
+
*/
|
|
45
|
+
export function buildToolObservation(block, runtime, workspaceDir) {
|
|
46
|
+
if (block.kind !== "tool_call" && block.kind !== "tool_result")
|
|
47
|
+
return null;
|
|
48
|
+
const fields = block.kind === "tool_call" ? CALL_FIELDS : RESULT_FIELDS;
|
|
49
|
+
const projected = collectAllowedFields(block.raw, fields);
|
|
50
|
+
if (typeof block.text === "string" && block.text) {
|
|
51
|
+
projected[block.kind === "tool_call" ? "target" : "summary"] = block.text;
|
|
52
|
+
}
|
|
53
|
+
const normalized = normalizeWorkspacePaths(redactSecretsDeep(projected), path.resolve(workspaceDir));
|
|
54
|
+
const serialized = Object.keys(projected).length > 0
|
|
55
|
+
? JSON.stringify(normalized, null, 2)
|
|
56
|
+
: "";
|
|
57
|
+
const detailTruncated = serialized.length > DETAIL_MAX_CHARS;
|
|
58
|
+
const detailPreview = detailTruncated
|
|
59
|
+
? `${serialized.slice(0, DETAIL_MAX_CHARS - 1)}…`
|
|
60
|
+
: serialized;
|
|
61
|
+
return {
|
|
62
|
+
schema_version: AGENT_TOOL_OBSERVATION_SCHEMA_VERSION,
|
|
63
|
+
kind: block.kind,
|
|
64
|
+
runtime,
|
|
65
|
+
status: block.kind === "tool_call"
|
|
66
|
+
? "started"
|
|
67
|
+
: block.status === "error"
|
|
68
|
+
? "error"
|
|
69
|
+
: "completed",
|
|
70
|
+
...(block.name && SAFE_TOOL_NAME.test(block.name) ? { name: block.name } : {}),
|
|
71
|
+
...(detailPreview ? { detail_preview: detailPreview } : {}),
|
|
72
|
+
detail_truncated: detailTruncated,
|
|
73
|
+
redacted: detailPreview.includes(REDACTED),
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
function collectAllowedFields(value, allowed, depth = 0, out = {}) {
|
|
77
|
+
if (value === null || typeof value !== "object" || depth >= MAX_PROJECT_DEPTH) {
|
|
78
|
+
return out;
|
|
79
|
+
}
|
|
80
|
+
if (Array.isArray(value)) {
|
|
81
|
+
for (const item of value.slice(0, 50)) {
|
|
82
|
+
collectAllowedFields(item, allowed, depth + 1, out);
|
|
83
|
+
}
|
|
84
|
+
return out;
|
|
85
|
+
}
|
|
86
|
+
for (const [key, item] of Object.entries(value)) {
|
|
87
|
+
if (allowed === RESULT_FIELDS
|
|
88
|
+
&& key === "content"
|
|
89
|
+
&& value.type === "tool_result") {
|
|
90
|
+
if (!("content" in out))
|
|
91
|
+
out.content = item;
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
if (allowed.has(key)) {
|
|
95
|
+
if (!(key in out))
|
|
96
|
+
out[key] = item;
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
collectAllowedFields(item, allowed, depth + 1, out);
|
|
100
|
+
}
|
|
101
|
+
return out;
|
|
102
|
+
}
|
|
103
|
+
function normalizeWorkspacePaths(value, workspaceDir) {
|
|
104
|
+
if (typeof value === "string") {
|
|
105
|
+
const normalizedWorkspace = workspaceDir.replaceAll("\\", "/").replace(/\/+$/, "");
|
|
106
|
+
const normalizedValue = value.replaceAll("\\", "/");
|
|
107
|
+
return normalizedValue
|
|
108
|
+
.replaceAll(`${normalizedWorkspace}/`, "")
|
|
109
|
+
.replaceAll(normalizedWorkspace, ".");
|
|
110
|
+
}
|
|
111
|
+
if (Array.isArray(value)) {
|
|
112
|
+
return value.map((item) => normalizeWorkspacePaths(item, workspaceDir));
|
|
113
|
+
}
|
|
114
|
+
if (value === null || typeof value !== "object")
|
|
115
|
+
return value;
|
|
116
|
+
return Object.fromEntries(Object.entries(value).map(([key, item]) => [
|
|
117
|
+
key,
|
|
118
|
+
normalizeWorkspacePaths(item, workspaceDir),
|
|
119
|
+
]));
|
|
120
|
+
}
|
package/dist/types.d.ts
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* `services/course-api/botlearn_course/schemas.py` 的 daemon 契约严格对齐。
|
|
6
6
|
*/
|
|
7
7
|
import type { ProgressStatus } from "./mcp/report-progress.js";
|
|
8
|
+
import type { PreparedRuntimeSkillProvider, RuntimeSkillEvent } from "./runtime-skills.js";
|
|
8
9
|
export interface RunInputAttachment {
|
|
9
10
|
attachment_id: string;
|
|
10
11
|
filename: string;
|
|
@@ -53,7 +54,7 @@ export interface RunStartPayload {
|
|
|
53
54
|
* `POST /daemon/runs/{id}/events` 接受的事件类型。
|
|
54
55
|
* 与后端 DaemonRunEventIn.type 的 Literal 严格一致 —— 发送其他类型会得到 422。
|
|
55
56
|
*/
|
|
56
|
-
export type RunEventType = "run.accepted" | "run.started" | "run.block" | "run.message" | "run.completed" | "run.failed" | "run.cancelled";
|
|
57
|
+
export type RunEventType = "run.accepted" | "run.started" | "run.block" | "run.observation" | "run.message" | "run.completed" | "run.failed" | "run.cancelled";
|
|
57
58
|
export interface RunEvent {
|
|
58
59
|
type: RunEventType;
|
|
59
60
|
/** End-to-end correlation id assigned by Course Service. */
|
|
@@ -125,7 +126,10 @@ export interface AppliedRunRuntimeProfile {
|
|
|
125
126
|
export interface RuntimeContentBlock {
|
|
126
127
|
kind: "text_delta" | "text" | "thinking" | "tool_call" | "tool_result" | "status" | "error";
|
|
127
128
|
text?: string;
|
|
128
|
-
/**
|
|
129
|
+
/**
|
|
130
|
+
* Safe provider-normalized tool identifier. Raw envelopes stay local; the dispatcher may
|
|
131
|
+
* derive a separate bounded/redacted teacher observation from explicit operation fields.
|
|
132
|
+
*/
|
|
129
133
|
name?: string;
|
|
130
134
|
/** Public lifecycle metadata; never carries provider reasoning or tool output. */
|
|
131
135
|
phase?: "in_progress" | "completed";
|
|
@@ -149,13 +153,26 @@ export interface RuntimeProgressDispositions {
|
|
|
149
153
|
}
|
|
150
154
|
/** Content-free model usage; adapters populate only fields actually reported upstream. */
|
|
151
155
|
export interface RuntimeUsage {
|
|
156
|
+
/** Model identity resolved by the runtime/provider, not inferred by the daemon. */
|
|
157
|
+
model?: string;
|
|
152
158
|
input_tokens?: number;
|
|
153
159
|
cached_input_tokens?: number;
|
|
154
160
|
output_tokens?: number;
|
|
161
|
+
reasoning_tokens?: number;
|
|
155
162
|
total_tokens?: number;
|
|
156
163
|
cost_usd?: number;
|
|
157
164
|
provider_request_ids?: string[];
|
|
158
165
|
}
|
|
166
|
+
/** Content-free shape of one runtime-native completion. */
|
|
167
|
+
export interface RuntimeCompletionSummary {
|
|
168
|
+
assistant_message_count: number;
|
|
169
|
+
reasoning_message_count: number;
|
|
170
|
+
assistant_content_present: boolean;
|
|
171
|
+
reasoning_content_present: boolean;
|
|
172
|
+
tool_call_count: number;
|
|
173
|
+
turn_status?: string;
|
|
174
|
+
finish_reason?: string;
|
|
175
|
+
}
|
|
159
176
|
export interface RuntimeAuthProbe {
|
|
160
177
|
checked: boolean;
|
|
161
178
|
ok: boolean;
|
|
@@ -179,6 +196,8 @@ export interface CourseRuntimeSink {
|
|
|
179
196
|
usage?(usage: RuntimeUsage): Promise<void>;
|
|
180
197
|
/** Persist the runtime-native thread/session id before a terminal turn event is emitted. */
|
|
181
198
|
runtimeSession?(sessionId: string): Promise<void>;
|
|
199
|
+
/** Content-free technical evidence from the control-side Runtime Skill Provider. */
|
|
200
|
+
skillEvent?(event: RuntimeSkillEvent): Promise<void>;
|
|
182
201
|
}
|
|
183
202
|
/** 一次 run 的本地执行上下文:服务器 payload + daemon 本地准备产物。 */
|
|
184
203
|
export interface RunExecution {
|
|
@@ -195,6 +214,8 @@ export interface RunExecution {
|
|
|
195
214
|
runtimeEnv?: NodeJS.ProcessEnv;
|
|
196
215
|
/** Verified learner files materialized beneath the runtime workspace. */
|
|
197
216
|
inputAttachments?: MaterializedInputAttachment[];
|
|
217
|
+
/** Activation-scoped provider held by the daemon control process, never runtime env. */
|
|
218
|
+
skillProvider?: PreparedRuntimeSkillProvider;
|
|
198
219
|
}
|
|
199
220
|
export interface CourseRuntime {
|
|
200
221
|
id: string;
|
|
@@ -226,7 +247,10 @@ export interface RuntimeFailureSummary {
|
|
|
226
247
|
stderr_tail?: string;
|
|
227
248
|
stdout_tail?: string;
|
|
228
249
|
error_name?: string;
|
|
250
|
+
error_code?: string;
|
|
229
251
|
error_message?: string;
|
|
252
|
+
model?: string;
|
|
253
|
+
completion?: RuntimeCompletionSummary;
|
|
230
254
|
}
|
|
231
255
|
export interface RuntimeModule {
|
|
232
256
|
id: string;
|
package/package.json
CHANGED