@downcity/agent 1.1.203 → 1.1.205

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 (62) hide show
  1. package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionExecutor.d.ts.map +1 -1
  2. package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionExecutor.js +3 -2
  3. package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionExecutor.js.map +1 -1
  4. package/bin/executor/composer/system/default/assets/core.prompt.d.ts +1 -1
  5. package/bin/executor/composer/system/default/assets/core.prompt.d.ts.map +1 -1
  6. package/bin/executor/composer/system/default/assets/core.prompt.js +1 -1
  7. package/bin/executor/composer/system/default/assets/core.prompt.js.map +1 -1
  8. package/bin/executor/composer/system/default/assets/init/PROFILE.md.d.ts +1 -1
  9. package/bin/executor/composer/system/default/assets/init/PROFILE.md.d.ts.map +1 -1
  10. package/bin/executor/composer/system/default/assets/init/PROFILE.md.js +1 -1
  11. package/bin/executor/composer/system/default/assets/init/PROFILE.md.js.map +1 -1
  12. package/bin/executor/composer/system/default/assets/init/SOUL.md.d.ts +1 -1
  13. package/bin/executor/composer/system/default/assets/init/SOUL.md.d.ts.map +1 -1
  14. package/bin/executor/composer/system/default/assets/init/SOUL.md.js +1 -1
  15. package/bin/executor/composer/system/default/assets/init/SOUL.md.js.map +1 -1
  16. package/bin/executor/composer/system/default/assets/plugin.prompt.d.ts +1 -1
  17. package/bin/executor/composer/system/default/assets/plugin.prompt.d.ts.map +1 -1
  18. package/bin/executor/composer/system/default/assets/plugin.prompt.js +1 -1
  19. package/bin/executor/composer/system/default/assets/plugin.prompt.js.map +1 -1
  20. package/bin/executor/composer/system/default/assets/task.prompt.d.ts +1 -1
  21. package/bin/executor/composer/system/default/assets/task.prompt.d.ts.map +1 -1
  22. package/bin/executor/composer/system/default/assets/task.prompt.js +1 -1
  23. package/bin/executor/composer/system/default/assets/task.prompt.js.map +1 -1
  24. package/bin/executor/composer/system/default/variables/VariableReplacer.js +1 -1
  25. package/bin/executor/composer/system/default/variables/VariableReplacer.js.map +1 -1
  26. package/bin/session/Session.d.ts.map +1 -1
  27. package/bin/session/Session.js +2 -0
  28. package/bin/session/Session.js.map +1 -1
  29. package/bin/session/SessionTitle.d.ts +9 -0
  30. package/bin/session/SessionTitle.d.ts.map +1 -1
  31. package/bin/session/SessionTitle.js +71 -6
  32. package/bin/session/SessionTitle.js.map +1 -1
  33. package/bin/session/services/SessionStateService.d.ts +6 -0
  34. package/bin/session/services/SessionStateService.d.ts.map +1 -1
  35. package/bin/session/services/SessionStateService.js +6 -0
  36. package/bin/session/services/SessionStateService.js.map +1 -1
  37. package/bin/session/services/SessionViewService.d.ts +6 -0
  38. package/bin/session/services/SessionViewService.d.ts.map +1 -1
  39. package/bin/session/services/SessionViewService.js +3 -0
  40. package/bin/session/services/SessionViewService.js.map +1 -1
  41. package/bin/types/runtime/auth/AuthPermission.js +3 -3
  42. package/bin/types/runtime/auth/AuthPermission.js.map +1 -1
  43. package/package.json +1 -1
  44. package/scripts/session-title-event.test.mjs +66 -0
  45. package/src/executor/composer/compaction/jsonl/JsonlSessionCompactionExecutor.ts +4 -2
  46. package/src/executor/composer/system/default/assets/core.prompt.ts +1 -1
  47. package/src/executor/composer/system/default/assets/core.prompt.ts.txt +44 -42
  48. package/src/executor/composer/system/default/assets/init/PROFILE.md.ts +1 -1
  49. package/src/executor/composer/system/default/assets/init/PROFILE.md.ts.txt +10 -11
  50. package/src/executor/composer/system/default/assets/init/SOUL.md.ts +1 -1
  51. package/src/executor/composer/system/default/assets/init/SOUL.md.ts.txt +58 -60
  52. package/src/executor/composer/system/default/assets/plugin.prompt.ts +1 -1
  53. package/src/executor/composer/system/default/assets/plugin.prompt.ts.txt +13 -13
  54. package/src/executor/composer/system/default/assets/task.prompt.ts +1 -1
  55. package/src/executor/composer/system/default/assets/task.prompt.ts.txt +28 -28
  56. package/src/executor/composer/system/default/variables/VariableReplacer.ts +1 -1
  57. package/src/session/Session.ts +2 -0
  58. package/src/session/SessionTitle.ts +138 -6
  59. package/src/session/services/SessionStateService.ts +12 -0
  60. package/src/session/services/SessionViewService.ts +9 -0
  61. package/src/types/runtime/auth/AuthPermission.ts +3 -3
  62. package/tsconfig.tsbuildinfo +1 -1
@@ -11,6 +11,7 @@ import { generateText, type LanguageModel } from "ai";
11
11
  import type { SessionHistoryMetaV1 } from "@/executor/types/SessionHistoryMeta.js";
12
12
  import type { SessionRecordV1 } from "@/executor/types/SessionRecords.js";
13
13
  import { is_session_message_record } from "@/executor/types/SessionRecords.js";
14
+ import type { Logger } from "@/utils/logger/Logger.js";
14
15
  import {
15
16
  normalizeSessionTitle,
16
17
  readSessionMetadata,
@@ -48,6 +49,16 @@ export interface EnsureSessionTitleParams {
48
49
  */
49
50
  model?: LanguageModel;
50
51
 
52
+ /**
53
+ * 当前模型展示标签;仅用于排障日志,不参与生成逻辑。
54
+ */
55
+ modelLabel?: string;
56
+
57
+ /**
58
+ * 当前 session 运行日志器;标题生成失败时仅记录摘要,不影响主流程。
59
+ */
60
+ logger?: Logger;
61
+
51
62
  /**
52
63
  * 是否允许调用模型生成标题。
53
64
  */
@@ -102,31 +113,135 @@ function normalizeGeneratedTitle(input: string): string | undefined {
102
113
  : undefined;
103
114
  }
104
115
 
116
+ function summarizeTitleError(error: unknown): {
117
+ /**
118
+ * 错误对象名称。
119
+ */
120
+ name: string | null;
121
+
122
+ /**
123
+ * 错误消息摘要。
124
+ */
125
+ message: string | null;
126
+
127
+ /**
128
+ * 字符串化后的错误摘要。
129
+ */
130
+ error: string;
131
+ } {
132
+ const record =
133
+ error && typeof error === "object" && !Array.isArray(error)
134
+ ? (error as Record<string, unknown>)
135
+ : {};
136
+ return {
137
+ name: typeof record.name === "string" ? record.name : null,
138
+ message: typeof record.message === "string" ? record.message : null,
139
+ error: String(error),
140
+ };
141
+ }
142
+
143
+ async function logSessionTitleDiagnostic(input: {
144
+ /**
145
+ * 当前 session 标识。
146
+ */
147
+ sessionId: string;
148
+
149
+ /**
150
+ * 日志级别。
151
+ */
152
+ level: "debug" | "warn";
153
+
154
+ /**
155
+ * 日志消息。
156
+ */
157
+ message: string;
158
+
159
+ /**
160
+ * 结构化日志字段。
161
+ */
162
+ details: Record<string, string | number | boolean | null | undefined>;
163
+
164
+ /**
165
+ * 当前 session 运行日志器。
166
+ */
167
+ logger?: Logger;
168
+ }): Promise<void> {
169
+ if (!input.logger) return;
170
+ try {
171
+ await input.logger.log(input.level, input.message, {
172
+ sessionId: input.sessionId,
173
+ ...input.details,
174
+ });
175
+ } catch {
176
+ // 关键点(中文):标题诊断日志失败不能影响 session 主流程。
177
+ }
178
+ }
179
+
105
180
  async function generateSessionTitle(input: {
106
181
  /**
107
182
  * 当前模型实例。
108
183
  */
109
184
  model: LanguageModel;
110
185
 
186
+ /**
187
+ * 当前 session 标识。
188
+ */
189
+ sessionId: string;
190
+
191
+ /**
192
+ * 当前模型展示标签;仅用于排障日志。
193
+ */
194
+ modelLabel?: string;
195
+
111
196
  /**
112
197
  * 首条用户消息文本。
113
198
  */
114
199
  firstUserText: string;
200
+
201
+ /**
202
+ * 当前 session 运行日志器。
203
+ */
204
+ logger?: Logger;
115
205
  }): Promise<string | undefined> {
116
206
  try {
117
207
  const result = await generateText({
118
208
  model: input.model,
119
209
  system:
120
- "你负责为一段会话生成极简标题。只输出标题本身,不要解释,不要使用引号。",
210
+ "You generate minimal conversation titles. Output only the title itself, with no explanation and no quotation marks.",
121
211
  prompt: [
122
- "根据下面这条用户首条消息,生成一个简短的会话标题。",
123
- "要求:3 12 个汉字或 2 6 个英文词;不要句号;不要前缀。",
212
+ "Generate a short conversation title from the first user message below.",
213
+ "Requirements: 3 to 12 Chinese characters or 2 to 6 English words; no period; no prefix.",
124
214
  "",
125
215
  input.firstUserText,
126
216
  ].join("\n"),
127
217
  });
128
- return normalizeGeneratedTitle(result.text);
129
- } catch {
218
+ const generatedTitle = normalizeGeneratedTitle(result.text);
219
+ if (!generatedTitle) {
220
+ await logSessionTitleDiagnostic({
221
+ logger: input.logger,
222
+ sessionId: input.sessionId,
223
+ level: "warn",
224
+ message: "[agent] session_title.empty",
225
+ details: {
226
+ modelLabel: input.modelLabel || null,
227
+ firstUserTextLength: input.firstUserText.length,
228
+ rawTitleLength: String(result.text || "").length,
229
+ },
230
+ });
231
+ }
232
+ return generatedTitle;
233
+ } catch (error) {
234
+ await logSessionTitleDiagnostic({
235
+ logger: input.logger,
236
+ sessionId: input.sessionId,
237
+ level: "warn",
238
+ message: "[agent] session_title.generate_failed",
239
+ details: {
240
+ modelLabel: input.modelLabel || null,
241
+ firstUserTextLength: input.firstUserText.length,
242
+ ...summarizeTitleError(error),
243
+ },
244
+ });
130
245
  // 关键点(中文):标题生成失败不能影响 session 主流程。
131
246
  return undefined;
132
247
  }
@@ -142,13 +257,30 @@ export async function ensureSessionTitle(
142
257
  if (current.title) return current;
143
258
 
144
259
  const firstUserText = resolveFirstUserText(input.messages);
145
- if (input.generate !== true || !input.model || !firstUserText) {
260
+ if (input.generate !== true) {
261
+ return current;
262
+ }
263
+ if (!input.model || !firstUserText) {
264
+ await logSessionTitleDiagnostic({
265
+ logger: input.logger,
266
+ sessionId: input.sessionId,
267
+ level: "debug",
268
+ message: "[agent] session_title.skipped",
269
+ details: {
270
+ reason: !input.model ? "missing_model" : "missing_first_user_text",
271
+ modelLabel: input.modelLabel || null,
272
+ messageCount: input.messages.length,
273
+ },
274
+ });
146
275
  return current;
147
276
  }
148
277
 
149
278
  const generatedTitle = await generateSessionTitle({
150
279
  model: input.model,
280
+ sessionId: input.sessionId,
281
+ modelLabel: input.modelLabel,
151
282
  firstUserText,
283
+ logger: input.logger,
152
284
  });
153
285
  if (!generatedTitle) return current;
154
286
 
@@ -41,6 +41,7 @@ import type {
41
41
  import { to_session_action_record } from "@/executor/types/SessionRecords.js";
42
42
  import type { SessionLocalState } from "@/types/session/SessionLocalState.js";
43
43
  import { generateId } from "@/utils/Id.js";
44
+ import type { Logger } from "@/utils/logger/Logger.js";
44
45
 
45
46
  type SessionStateServiceOptions = {
46
47
  /**
@@ -73,6 +74,11 @@ type SessionStateServiceOptions = {
73
74
  */
74
75
  state: SessionLocalState;
75
76
 
77
+ /**
78
+ * 当前 session 运行日志器。
79
+ */
80
+ logger: Logger;
81
+
76
82
  /**
77
83
  * 在执行前补齐宿主级配置。
78
84
  */
@@ -107,6 +113,7 @@ export class SessionStateService {
107
113
  private readonly history_store: JsonlSessionHistoryStore;
108
114
  private readonly executor: Executor;
109
115
  private readonly state: SessionLocalState;
116
+ private readonly logger: Logger;
110
117
  private readonly ensure_configured_hook?: SessionStateServiceOptions["ensure_configured_hook"];
111
118
  private readonly publish_event: SessionStateServiceOptions["publish_event"];
112
119
 
@@ -117,6 +124,7 @@ export class SessionStateService {
117
124
  this.history_store = options.history_store;
118
125
  this.executor = options.executor;
119
126
  this.state = options.state;
127
+ this.logger = options.logger;
120
128
  this.ensure_configured_hook = options.ensure_configured_hook;
121
129
  this.publish_event = options.publish_event;
122
130
  }
@@ -340,6 +348,10 @@ export class SessionStateService {
340
348
  sessionId: this.session_id,
341
349
  messages,
342
350
  ...(input?.generate ? { model: this.state.sessionConfig.model } : {}),
351
+ ...(this.state.sessionConfig.modelLabel
352
+ ? { modelLabel: this.state.sessionConfig.modelLabel }
353
+ : {}),
354
+ logger: this.logger,
343
355
  generate: input?.generate === true,
344
356
  });
345
357
  const next_title = String(next_metadata.title || "").trim();
@@ -31,6 +31,7 @@ import type {
31
31
  import type { SessionRecordV1 } from "@/executor/types/SessionRecords.js";
32
32
  import { SessionStateService } from "@/session/services/SessionStateService.js";
33
33
  import type { SessionRunContext } from "@/types/executor/SessionRunContext.js";
34
+ import type { Logger } from "@/utils/logger/Logger.js";
34
35
 
35
36
  type SessionViewServiceOptions<TSession extends Pick<AgentSession, "set">> = {
36
37
  /**
@@ -58,6 +59,11 @@ type SessionViewServiceOptions<TSession extends Pick<AgentSession, "set">> = {
58
59
  */
59
60
  state_service: SessionStateService;
60
61
 
62
+ /**
63
+ * 当前 session 运行日志器。
64
+ */
65
+ logger: Logger;
66
+
61
67
  /**
62
68
  * 判断当前 session 是否正在执行。
63
69
  */
@@ -106,6 +112,7 @@ export class SessionViewService<TSession extends Pick<AgentSession, "set">> {
106
112
  private readonly session_id: string;
107
113
  private readonly history_store: JsonlSessionHistoryStore;
108
114
  private readonly state_service: SessionStateService;
115
+ private readonly logger: Logger;
109
116
  private readonly is_executing: SessionViewServiceOptions<TSession>["is_executing"];
110
117
  private readonly get_instruction_system_blocks: SessionViewServiceOptions<TSession>["get_instruction_system_blocks"];
111
118
  private readonly get_managed_plugin_system_blocks: SessionViewServiceOptions<TSession>["get_managed_plugin_system_blocks"];
@@ -119,6 +126,7 @@ export class SessionViewService<TSession extends Pick<AgentSession, "set">> {
119
126
  this.session_id = options.session_id;
120
127
  this.history_store = options.history_store;
121
128
  this.state_service = options.state_service;
129
+ this.logger = options.logger;
122
130
  this.is_executing = options.is_executing;
123
131
  this.get_instruction_system_blocks = options.get_instruction_system_blocks;
124
132
  this.get_managed_plugin_system_blocks =
@@ -164,6 +172,7 @@ export class SessionViewService<TSession extends Pick<AgentSession, "set">> {
164
172
  agentId: this.agent_id,
165
173
  sessionId: this.session_id,
166
174
  messages: input.messages,
175
+ logger: this.logger,
167
176
  });
168
177
  return buildSessionInfo({
169
178
  projectRoot: this.project_root,
@@ -93,19 +93,19 @@ export interface AuthDefaultRoleDefinition {
93
93
  export const AUTH_DEFAULT_ROLES: AuthDefaultRoleDefinition[] = [
94
94
  {
95
95
  name: "admin",
96
- description: "系统管理员,可管理统一账户与所有控制面能力。",
96
+ description: "System administrator who can manage unified accounts and all control-plane capabilities.",
97
97
  permissions: [...AUTH_PERMISSION_KEYS],
98
98
  },
99
99
  {
100
100
  name: "operator",
101
- description: "运维角色,可查看并操作运行时,但不管理统一账户。",
101
+ description: "Operations role that can view and operate the runtime but cannot manage unified accounts.",
102
102
  permissions: AUTH_PERMISSION_KEYS.filter((permission) =>
103
103
  permission !== "auth.write" && permission !== "auth.read"
104
104
  ),
105
105
  },
106
106
  {
107
107
  name: "viewer",
108
- description: "只读角色,可查看状态但不能执行高危变更。",
108
+ description: "Read-only role that can view status but cannot perform high-risk changes.",
109
109
  permissions: [
110
110
  "agent.read",
111
111
  "task.read",