@downcity/agent 1.1.17 → 1.1.18
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 +4 -5
- package/bin/core/AgentCore.d.ts +2 -1
- package/bin/core/AgentCore.d.ts.map +1 -1
- package/bin/core/AgentCore.js +15 -7
- package/bin/core/AgentCore.js.map +1 -1
- package/bin/core/AgentCoreTypes.d.ts +7 -3
- package/bin/core/AgentCoreTypes.d.ts.map +1 -1
- package/bin/sdk/AgentSdkTypes.d.ts +12 -1
- package/bin/sdk/AgentSdkTypes.d.ts.map +1 -1
- package/bin/sdk/Session.d.ts +14 -0
- package/bin/sdk/Session.d.ts.map +1 -1
- package/bin/sdk/Session.js +32 -2
- package/bin/sdk/Session.js.map +1 -1
- package/bin/sdk/session/ServicePort.d.ts +4 -0
- package/bin/sdk/session/ServicePort.d.ts.map +1 -1
- package/bin/sdk/session/ServicePort.js +1 -0
- package/bin/sdk/session/ServicePort.js.map +1 -1
- package/bin/session/Executor.js +1 -1
- package/bin/session/Executor.js.map +1 -1
- package/package.json +1 -1
- package/src/core/AgentCore.ts +20 -11
- package/src/core/AgentCoreTypes.ts +7 -3
- package/src/sdk/AgentSdkTypes.ts +13 -1
- package/src/sdk/Session.ts +40 -2
- package/src/sdk/session/ServicePort.ts +5 -0
- package/src/session/Executor.ts +1 -1
- package/tsconfig.tsbuildinfo +1 -1
package/src/core/AgentCore.ts
CHANGED
|
@@ -4,15 +4,16 @@
|
|
|
4
4
|
* 关键点(中文)
|
|
5
5
|
* - 一个 `AgentCore` 只服务一个 agent 实例,不依赖进程级 singleton runtime。
|
|
6
6
|
* - SDK `Agent`、实例绑定式 HTTP server、实例绑定式 local RPC 都应基于它工作。
|
|
7
|
-
* - 宿主若需要统一 session 默认配置,应通过 `configureSession` 注入,而不是把策略写死在 SDK 中。
|
|
7
|
+
* - 宿主若需要统一 session 默认配置,应通过 `model` / `configureSession` 注入,而不是把策略写死在 SDK 中。
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import fs from "fs-extra";
|
|
11
11
|
import { nanoid } from "nanoid";
|
|
12
|
-
import type { Tool } from "ai";
|
|
12
|
+
import type { LanguageModel, Tool } from "ai";
|
|
13
13
|
import { Logger } from "@/utils/logger/Logger.js";
|
|
14
14
|
import type { BaseService } from "@/service/builtins/BaseService.js";
|
|
15
15
|
import type { AgentContext } from "@/core/AgentContextTypes.js";
|
|
16
|
+
import type { SessionPort } from "@/core/AgentContextTypes.js";
|
|
16
17
|
import type { AgentRuntime } from "@/core/AgentCoreTypes.js";
|
|
17
18
|
import type { DowncityConfig } from "@/types/config/DowncityConfig.js";
|
|
18
19
|
import type { JsonValue } from "@/types/common/Json.js";
|
|
@@ -127,6 +128,7 @@ export class AgentCore {
|
|
|
127
128
|
private readonly platform: AgentPlatformRuntime;
|
|
128
129
|
private readonly env: Record<string, string>;
|
|
129
130
|
private readonly globalEnv: Record<string, string>;
|
|
131
|
+
private readonly defaultModel?: LanguageModel;
|
|
130
132
|
private readonly configureSessionHook?: AgentOptions["configureSession"];
|
|
131
133
|
private instruction: string[];
|
|
132
134
|
private servicesStartPromise: Promise<void> | null = null;
|
|
@@ -151,6 +153,7 @@ export class AgentCore {
|
|
|
151
153
|
this.globalEnv = this.platform.getGlobalEnv?.() || {};
|
|
152
154
|
this.env = this.platform.getAgentEnv?.(this.path) || {};
|
|
153
155
|
this.instruction = normalizeInstructionInput(options.instruction);
|
|
156
|
+
this.defaultModel = options.model;
|
|
154
157
|
this.configureSessionHook = options.configureSession;
|
|
155
158
|
this.config = this.loadConfig();
|
|
156
159
|
this.services = new Map<string, BaseService>();
|
|
@@ -400,9 +403,8 @@ export class AgentCore {
|
|
|
400
403
|
paths: createAgentPathRuntime(this.path),
|
|
401
404
|
pluginConfig: createAgentPluginConfigRuntime(this.path),
|
|
402
405
|
platform: this.platform,
|
|
403
|
-
getSession: (sessionId: string) =>
|
|
404
|
-
|
|
405
|
-
},
|
|
406
|
+
getSession: (sessionId: string): SessionPort =>
|
|
407
|
+
this.getOrCreateSession(sessionId).getServicePort(),
|
|
406
408
|
listExecutingSessionIds: () =>
|
|
407
409
|
[...this.sessionsById.values()]
|
|
408
410
|
.filter((session) => session.isExecuting())
|
|
@@ -410,10 +412,8 @@ export class AgentCore {
|
|
|
410
412
|
getExecutingSessionCount: () =>
|
|
411
413
|
[...this.sessionsById.values()].filter((session) => session.isExecuting()).length,
|
|
412
414
|
services: this.services,
|
|
413
|
-
} satisfies
|
|
414
|
-
|
|
415
|
-
};
|
|
416
|
-
return runtime as unknown as AgentRuntime;
|
|
415
|
+
} satisfies AgentRuntime;
|
|
416
|
+
return runtime;
|
|
417
417
|
}
|
|
418
418
|
|
|
419
419
|
private createServiceContext(): AgentContext {
|
|
@@ -516,15 +516,24 @@ export class AgentCore {
|
|
|
516
516
|
getInstructionSystemBlocks: () => this.loadInstructionSystemBlocks(),
|
|
517
517
|
getServiceSystemBlocks: () => this.loadServiceSystemBlocks(),
|
|
518
518
|
getPluginSystemBlocks: () => this.loadPluginSystemBlocks(),
|
|
519
|
+
ensureConfigured: async (session) => {
|
|
520
|
+
await this.configureSession(session);
|
|
521
|
+
},
|
|
519
522
|
});
|
|
520
523
|
this.sessionsById.set(resolvedSessionId, created);
|
|
521
524
|
return created;
|
|
522
525
|
}
|
|
523
526
|
|
|
524
527
|
private async configureSession(session: Session): Promise<void> {
|
|
525
|
-
if (!this.configureSessionHook) return;
|
|
526
528
|
if (this.configuredSessionIds.has(session.id)) return;
|
|
527
|
-
|
|
529
|
+
if (this.defaultModel) {
|
|
530
|
+
await session.set({
|
|
531
|
+
model: this.defaultModel,
|
|
532
|
+
});
|
|
533
|
+
}
|
|
534
|
+
if (this.configureSessionHook) {
|
|
535
|
+
await this.configureSessionHook(session);
|
|
536
|
+
}
|
|
528
537
|
this.configuredSessionIds.add(session.id);
|
|
529
538
|
}
|
|
530
539
|
}
|
|
@@ -15,7 +15,7 @@ import type {
|
|
|
15
15
|
AgentPluginConfigRuntime,
|
|
16
16
|
} from "@/types/runtime/host/AgentHost.js";
|
|
17
17
|
import type { BaseService } from "@/service/builtins/BaseService.js";
|
|
18
|
-
import type {
|
|
18
|
+
import type { SessionPort } from "@/core/AgentContextTypes.js";
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
21
|
* AgentCore 启动早期的基础状态。
|
|
@@ -68,9 +68,13 @@ export interface AgentRuntimeBase {
|
|
|
68
68
|
*/
|
|
69
69
|
export interface AgentRuntime extends AgentRuntimeBase {
|
|
70
70
|
/**
|
|
71
|
-
* 读取指定 sessionId
|
|
71
|
+
* 读取指定 sessionId 对应的 session 端口。
|
|
72
|
+
*
|
|
73
|
+
* 关键点(中文)
|
|
74
|
+
* - 返回值是统一的 `SessionPort`,而不是裸 `Executor`。
|
|
75
|
+
* - 这样 HTTP / service / chat queue / contact 等入口都能复用同一层会话装配与执行兜底。
|
|
72
76
|
*/
|
|
73
|
-
getSession(sessionId: string):
|
|
77
|
+
getSession(sessionId: string): SessionPort;
|
|
74
78
|
/**
|
|
75
79
|
* 返回当前执行中的 sessionId 列表。
|
|
76
80
|
*/
|
package/src/sdk/AgentSdkTypes.ts
CHANGED
|
@@ -54,6 +54,16 @@ export interface AgentOptions {
|
|
|
54
54
|
*/
|
|
55
55
|
instruction?: string | string[];
|
|
56
56
|
|
|
57
|
+
/**
|
|
58
|
+
* 当前 agent 为新建 session 提供的默认模型实例。
|
|
59
|
+
*
|
|
60
|
+
* 关键点(中文)
|
|
61
|
+
* - SDK 仍不负责“选择哪个模型”,这里只接收宿主已经创建好的 `LanguageModel`。
|
|
62
|
+
* - 该模型会作为 session 首次执行前的默认注入值。
|
|
63
|
+
* - 若同时提供 `configureSession`,则先应用这里的默认模型,再允许宿主继续覆写。
|
|
64
|
+
*/
|
|
65
|
+
model?: LanguageModel;
|
|
66
|
+
|
|
57
67
|
/**
|
|
58
68
|
* 当前 agent 显式持有的 service 实例集合。
|
|
59
69
|
*
|
|
@@ -106,7 +116,9 @@ export interface AgentOptions {
|
|
|
106
116
|
*
|
|
107
117
|
* 关键点(中文)
|
|
108
118
|
* - SDK 不负责默认模型策略,宿主可在这里统一为 session 注入 model 等运行配置。
|
|
109
|
-
* -
|
|
119
|
+
* - 若同时传入 `model`,则会先写入默认模型,再执行这里的宿主覆写逻辑。
|
|
120
|
+
* - 该钩子对每个 session 只触发一次,适合做实例级默认装配。
|
|
121
|
+
* - 触发时机可能来自显式 `agent.session()`,也可能来自该 session 的首次执行入口。
|
|
110
122
|
*/
|
|
111
123
|
configureSession?: (session: Session) => Promise<void> | void;
|
|
112
124
|
}
|
package/src/sdk/Session.ts
CHANGED
|
@@ -92,6 +92,15 @@ type SessionOptions = {
|
|
|
92
92
|
* 读取当前 agent 显式注册 plugin 的 system blocks。
|
|
93
93
|
*/
|
|
94
94
|
getPluginSystemBlocks: () => Promise<AgentSessionSystemBlock[]>;
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* 在执行前确保当前 session 已完成宿主侧默认配置。
|
|
98
|
+
*
|
|
99
|
+
* 关键点(中文)
|
|
100
|
+
* - 这里通常由 `AgentCore` 注入,用于补齐默认 model、宿主覆写等一次性装配。
|
|
101
|
+
* - 所有执行入口都应通过这里兜底,避免只在 SDK `agent.session()` 链路上做配置。
|
|
102
|
+
*/
|
|
103
|
+
ensureConfigured?: (session: Session) => Promise<void>;
|
|
95
104
|
};
|
|
96
105
|
|
|
97
106
|
/**
|
|
@@ -107,6 +116,7 @@ export class Session {
|
|
|
107
116
|
private readonly getInstructionSystemBlocks: SessionOptions["getInstructionSystemBlocks"];
|
|
108
117
|
private readonly getServiceSystemBlocks: SessionOptions["getServiceSystemBlocks"];
|
|
109
118
|
private readonly getPluginSystemBlocks: SessionOptions["getPluginSystemBlocks"];
|
|
119
|
+
private readonly ensureConfiguredHook?: SessionOptions["ensureConfigured"];
|
|
110
120
|
private readonly historyStore: JsonlSessionHistoryStore;
|
|
111
121
|
private readonly historyComposer: JsonlSessionHistoryComposer;
|
|
112
122
|
private readonly executor: Executor;
|
|
@@ -114,6 +124,7 @@ export class Session {
|
|
|
114
124
|
private createdAt = Date.now();
|
|
115
125
|
private timezone = resolveSystemTimezone();
|
|
116
126
|
private initializePromise: Promise<this> | null = null;
|
|
127
|
+
private ensureConfiguredPromise: Promise<void> | null = null;
|
|
117
128
|
private servicePort: SessionPort | null = null;
|
|
118
129
|
|
|
119
130
|
constructor(options: SessionOptions) {
|
|
@@ -125,6 +136,7 @@ export class Session {
|
|
|
125
136
|
this.getInstructionSystemBlocks = options.getInstructionSystemBlocks;
|
|
126
137
|
this.getServiceSystemBlocks = options.getServiceSystemBlocks;
|
|
127
138
|
this.getPluginSystemBlocks = options.getPluginSystemBlocks;
|
|
139
|
+
this.ensureConfiguredHook = options.ensureConfigured;
|
|
128
140
|
if (!this.id) {
|
|
129
141
|
throw new Error("Session requires a non-empty sessionId");
|
|
130
142
|
}
|
|
@@ -338,9 +350,10 @@ export class Session {
|
|
|
338
350
|
if (!query) {
|
|
339
351
|
throw new Error("session.run requires a non-empty query");
|
|
340
352
|
}
|
|
353
|
+
await this.ensureReadyForExecution();
|
|
341
354
|
if (!this.sessionConfig.model) {
|
|
342
355
|
throw new Error(
|
|
343
|
-
`Session "${this.id}" requires a configured model.
|
|
356
|
+
`Session "${this.id}" requires a configured model. Pass model to new Agent({ model }), call session.set({ model }) first, or let the host configure the session during creation.`,
|
|
344
357
|
);
|
|
345
358
|
}
|
|
346
359
|
await this.appendUserMessage({ text: query });
|
|
@@ -366,9 +379,10 @@ export class Session {
|
|
|
366
379
|
if (!query) {
|
|
367
380
|
throw new Error("session.stream requires a non-empty query");
|
|
368
381
|
}
|
|
382
|
+
await this.ensureReadyForExecution();
|
|
369
383
|
if (!this.sessionConfig.model) {
|
|
370
384
|
throw new Error(
|
|
371
|
-
`Session "${this.id}" requires a configured model.
|
|
385
|
+
`Session "${this.id}" requires a configured model. Pass model to new Agent({ model }), call session.set({ model }) first, or let the host configure the session during creation.`,
|
|
372
386
|
);
|
|
373
387
|
}
|
|
374
388
|
const queue = new AsyncQueue<AgentSessionStreamEvent>();
|
|
@@ -478,6 +492,9 @@ export class Session {
|
|
|
478
492
|
sessionId: this.id,
|
|
479
493
|
executor: this.executor,
|
|
480
494
|
historyStore: this.historyStore,
|
|
495
|
+
ensureReadyForExecution: async () => {
|
|
496
|
+
await this.ensureReadyForExecution();
|
|
497
|
+
},
|
|
481
498
|
touchMetadata: async () => {
|
|
482
499
|
await this.touchMetadata();
|
|
483
500
|
},
|
|
@@ -485,6 +502,27 @@ export class Session {
|
|
|
485
502
|
return this.servicePort;
|
|
486
503
|
}
|
|
487
504
|
|
|
505
|
+
/**
|
|
506
|
+
* 在执行前确保 session 已完成初始化与宿主装配。
|
|
507
|
+
*/
|
|
508
|
+
async ensureReadyForExecution(): Promise<void> {
|
|
509
|
+
await this.initialize();
|
|
510
|
+
if (this.ensureConfiguredPromise) {
|
|
511
|
+
await this.ensureConfiguredPromise;
|
|
512
|
+
return;
|
|
513
|
+
}
|
|
514
|
+
this.ensureConfiguredPromise = (async () => {
|
|
515
|
+
if (!this.ensureConfiguredHook) return;
|
|
516
|
+
await this.ensureConfiguredHook(this);
|
|
517
|
+
})();
|
|
518
|
+
try {
|
|
519
|
+
await this.ensureConfiguredPromise;
|
|
520
|
+
} catch (error) {
|
|
521
|
+
this.ensureConfiguredPromise = null;
|
|
522
|
+
throw error;
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
|
|
488
526
|
private async touchMetadata(): Promise<void> {
|
|
489
527
|
await touchSessionMetadata({
|
|
490
528
|
projectRoot: this.projectRoot,
|
|
@@ -25,6 +25,10 @@ export interface CreateSessionServicePortParams {
|
|
|
25
25
|
* 当前 session 历史持久化端口。
|
|
26
26
|
*/
|
|
27
27
|
historyStore: SessionHistoryStore;
|
|
28
|
+
/**
|
|
29
|
+
* 在执行前确保当前 session 已完成初始化与宿主级配置。
|
|
30
|
+
*/
|
|
31
|
+
ensureReadyForExecution: () => Promise<void>;
|
|
28
32
|
/**
|
|
29
33
|
* session 更新后需要同步执行的持久化回调。
|
|
30
34
|
*/
|
|
@@ -42,6 +46,7 @@ export function createSessionServicePort(
|
|
|
42
46
|
getExecutor: () => params.executor.getExecutor(),
|
|
43
47
|
getHistoryStore: () => params.historyStore,
|
|
44
48
|
run: async (runParams) => {
|
|
49
|
+
await params.ensureReadyForExecution();
|
|
45
50
|
return await params.executor.run(runParams);
|
|
46
51
|
},
|
|
47
52
|
clearExecutor: () => {
|
package/src/session/Executor.ts
CHANGED
|
@@ -717,7 +717,7 @@ export class Executor implements SessionExecutor {
|
|
|
717
717
|
const model = this.getModel();
|
|
718
718
|
if (!model) {
|
|
719
719
|
throw new Error(
|
|
720
|
-
`Executor for session "${this.sessionId}" requires a configured model
|
|
720
|
+
`Executor for session "${this.sessionId}" requires a configured model. Pass model to new Agent({ model }), call session.set({ model }), or let the host configure the session before execution.`,
|
|
721
721
|
);
|
|
722
722
|
}
|
|
723
723
|
return model;
|