evolcore 0.0.3 → 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/CHANGELOG.md +83 -0
- package/README.md +45 -10
- package/bin/ec-safe-output.js +89 -24
- package/dist/agents/baseagent.js +46 -0
- package/dist/agents/claude-runner.js +1 -31
- package/dist/agents/codex-app-server-client.js +68 -0
- package/dist/agents/codex-runner.js +157 -5
- package/dist/agents/runner-types.js +2 -2
- package/dist/aun/aid/agentmd.js +79 -0
- package/dist/aun/aid/encryption-seed-policy.js +29 -0
- package/dist/aun/aid/index.js +1 -1
- package/dist/aun/aid/store.js +2 -5
- package/dist/channels/aun.js +220 -112
- package/dist/channels/daemon.js +18 -4
- package/dist/channels/dingtalk.js +52 -137
- package/dist/channels/feishu.js +56 -4
- package/dist/channels/qqbot.js +23 -1
- package/dist/channels/wechat.js +303 -155
- package/dist/channels/wecom.js +383 -7
- package/dist/cli/aun-commands.js +11 -11
- package/dist/cli/daemon-commands.js +46 -15
- package/dist/cli/handoff-command.js +2 -1
- package/dist/cli/init-channel.js +185 -67
- package/dist/cli/init.js +49 -27
- package/dist/cli/trigger-command.js +92 -11
- package/dist/config/access-policy-domain.js +18 -0
- package/dist/config/access-policy.js +110 -0
- package/dist/config/builtin-role-templates.js +27 -14
- package/dist/config/builtin-roles.js +25 -6
- package/dist/config/config-field-policy.js +17 -5
- package/dist/config/config-manager.js +198 -22
- package/dist/config/config-operation-service.js +35 -38
- package/dist/config/contact-bind-code.js +274 -0
- package/dist/config/contact-book-store.js +173 -5
- package/dist/config/contact-book.js +32 -0
- package/dist/config/contact-operation-service.js +9 -3
- package/dist/config/contact-request-service.js +331 -0
- package/dist/config/peer-role-resolver.js +3 -1
- package/dist/config/schema-registry.js +49 -24
- package/dist/config-store.js +14 -2
- package/dist/core/auth/agent-delegation.js +105 -11
- package/dist/core/auth/authorization-audit.js +6 -0
- package/dist/core/auth/operation-authorizer.js +8 -0
- package/dist/core/auth/operation-catalog.js +51 -3
- package/dist/core/auth/trigger-authorization.js +15 -0
- package/dist/core/bootstrap-service.js +2 -9
- package/dist/core/channel-loader.js +6 -2
- package/dist/core/command/command-handler.js +10 -13
- package/dist/core/command/connect-menu.js +229 -26
- package/dist/core/command/evol-menu-version-gate.js +38 -0
- package/dist/core/command/group-menu.js +421 -0
- package/dist/core/command/menu-handler.js +269 -85
- package/dist/core/command/menu-protocol.js +8 -2
- package/dist/core/command/menu-token-store.js +102 -0
- package/dist/core/command/role-menu.js +16 -0
- package/dist/core/command/slash-gate.js +1 -1
- package/dist/core/command/slash-handler.js +158 -31
- package/dist/core/daemon-file-cache.js +28 -0
- package/dist/core/event-catalog.js +29 -0
- package/dist/core/evolagent-registry.js +4 -39
- package/dist/core/handoff/runtime.js +162 -37
- package/dist/core/handoff/store.js +46 -2
- package/dist/core/handoff/types.js +1 -0
- package/dist/core/inference/text-inference.js +16 -74
- package/dist/core/message/file-markers.js +7 -0
- package/dist/core/message/im-renderer.js +18 -14
- package/dist/core/message/inbound-admission.js +134 -0
- package/dist/core/message/message-bridge.js +616 -74
- package/dist/core/message/message-log.js +1 -0
- package/dist/core/message/message-queue.js +185 -10
- package/dist/core/message/peer-mode.js +7 -8
- package/dist/core/message/response-engine.js +381 -79
- package/dist/core/permission/approval-gateway.js +17 -10
- package/dist/core/permission/ec-command-parser.js +101 -46
- package/dist/core/permission/tool-policy.js +69 -24
- package/dist/core/protected-paths.js +36 -11
- package/dist/core/session/session-fs-store.js +19 -4
- package/dist/core/session/session-manager.js +232 -4
- package/dist/core/session/session-mapper.js +2 -0
- package/dist/core/session/session-renew.js +125 -69
- package/dist/core/session/session-turn-coordinator.js +5 -1
- package/dist/eck/kit-renderer.js +12 -1
- package/dist/eck/message-renderer.js +79 -1
- package/dist/index.js +224 -89
- package/dist/ipc.js +81 -4
- package/dist/paths.js +3 -0
- package/dist/response-system/config-resolver.js +29 -0
- package/dist/response-system/coordinator.js +8 -32
- package/dist/response-system/engines/v1/proactive-flow.js +1 -1
- package/dist/response-system/index.js +1 -0
- package/dist/response-system/modes/single-session/index.js +7 -4
- package/dist/trigger/parser.js +55 -15
- package/dist/trigger/patch.js +4 -1
- package/dist/trigger/scheduler.js +441 -39
- package/dist/utils/cross-platform.js +8 -2
- package/dist/utils/error-dict.json +7 -0
- package/dist/utils/evolcore-version.js +21 -0
- package/dist/utils/logger.js +2 -2
- package/dist/utils/process-introspect.js +19 -3
- package/dist/utils/stable-semver.js +21 -0
- package/dist/utils/stats.js +33 -9
- package/kits/docs/channels/aun.md +4 -13
- package/kits/docs/evolcore/INDEX.md +1 -1
- package/kits/docs/evolcore/config.md +47 -2
- package/kits/docs/evolcore/contact.md +8 -3
- package/kits/docs/evolcore/group-rules.md +46 -4
- package/kits/docs/evolcore/group.md +4 -4
- package/kits/docs/evolcore/msg.md +5 -5
- package/kits/docs/evolcore/trigger.md +25 -8
- package/kits/docs/path-registry.md +36 -17
- package/kits/eck_message_manifest.json +12 -1
- package/kits/migrations/migrate-contact-book-v2.mjs +7 -0
- package/kits/rules/01-overview.md +17 -7
- package/kits/rules/02-navigation.md +38 -18
- package/kits/rules/03-identity.md +28 -24
- package/kits/rules/04-relation.md +44 -28
- package/kits/rules/05-venue.md +31 -15
- package/kits/rules/06-channel.md +11 -7
- package/kits/schemas/_meta.json +18 -7
- package/kits/schemas/agent-config.schema.7.json +303 -0
- package/kits/schemas/agent-config.schema.8.json +304 -0
- package/kits/schemas/agent-config.schema.9.json +364 -0
- package/kits/schemas/contact-book.schema.3.json +67 -0
- package/kits/schemas/daemon.schema.1.json +3 -2
- package/kits/schemas/daemon.schema.2.json +101 -0
- package/kits/schemas/daemon.schema.3.json +123 -0
- package/kits/schemas/defaults.schema.2.json +85 -0
- package/kits/schemas/defaults.schema.3.json +73 -0
- package/kits/schemas/relation-config.schema.6.json +46 -0
- package/kits/schemas/relation-config.schema.7.json +59 -0
- package/kits/schemas/single-session.schema.2.json +57 -0
- package/kits/templates/message-fragments/handoff-context-to-target.md +9 -0
- package/kits/templates/message-fragments/handoff-request-to-target.md +14 -8
- package/kits/templates/message-fragments/handoff-response-to-origin.md +5 -6
- package/kits/templates/roles/admin.json +46 -0
- package/kits/templates/roles/member.json +4 -0
- package/kits/templates/roles/visitor.json +4 -0
- package/kits/templates/system-fragments/channel.md +12 -2
- package/kits/templates/system-fragments/identity.md +3 -1
- package/kits/templates/system-fragments/relation.md +1 -1
- package/kits/templates/system-fragments/session.md +6 -2
- package/package.json +4 -2
- package/MIGRATION-0.5.0.md +0 -378
- package/ROLE_ACCESS_CONTROL.md +0 -174
- package/dist/channels/contact-bind-code.js +0 -134
- package/dist/channels/wecom-card.js +0 -101
- package/dist/channels/wecom-onboarding.js +0 -82
- package/dist/channels/wecom-state.js +0 -191
package/dist/ipc.js
CHANGED
|
@@ -9,6 +9,7 @@ import { resolvePaths } from './paths.js';
|
|
|
9
9
|
import { getProcessStartTime, isSameOrOlderProcess } from './utils/process-introspect.js';
|
|
10
10
|
import { classifyProcessTree, ProcessTreeSampler } from './utils/process-tree-stats.js';
|
|
11
11
|
import { readSystemMemoryUsage } from './utils/system-memory.js';
|
|
12
|
+
import { hashCurrentDelegatedCommand } from './core/auth/agent-delegation.js';
|
|
12
13
|
const isWindows = process.platform === 'win32';
|
|
13
14
|
const isNamedPipe = (p) => isWindows && p.startsWith('\\\\.\\pipe\\');
|
|
14
15
|
export function summarizeMonitorAgents(agents, aids) {
|
|
@@ -48,7 +49,10 @@ export class IpcServer {
|
|
|
48
49
|
configOperationExecutor;
|
|
49
50
|
contactOperationExecutor;
|
|
50
51
|
dingtalkContactBindExecutor;
|
|
52
|
+
feishuContactBindExecutor;
|
|
53
|
+
qqbotContactBindExecutor;
|
|
51
54
|
wecomContactBindExecutor;
|
|
55
|
+
wechatContactBindExecutor;
|
|
52
56
|
// CPU 占用追踪:IPC handler 是一次性同步调用,无法在响应里做 200ms 异步采样,
|
|
53
57
|
// 故用后台 1s interval 累积 process.cpuUsage() 增量,handler 直接读最近值。
|
|
54
58
|
// procCpuPercent = 本 daemon 进程占单核的百分比(可 >100% 仅当多核,已 clamp 到 100);
|
|
@@ -142,10 +146,22 @@ export class IpcServer {
|
|
|
142
146
|
setDingtalkContactBindExecutor(executor) {
|
|
143
147
|
this.dingtalkContactBindExecutor = executor;
|
|
144
148
|
}
|
|
149
|
+
/** Inject Feishu contact binding-code executor. */
|
|
150
|
+
setFeishuContactBindExecutor(executor) {
|
|
151
|
+
this.feishuContactBindExecutor = executor;
|
|
152
|
+
}
|
|
153
|
+
/** Inject QQ contact binding-code executor. */
|
|
154
|
+
setQQBotContactBindExecutor(executor) {
|
|
155
|
+
this.qqbotContactBindExecutor = executor;
|
|
156
|
+
}
|
|
145
157
|
/** Inject WeCom contact binding-code executor. */
|
|
146
158
|
setWecomContactBindExecutor(executor) {
|
|
147
159
|
this.wecomContactBindExecutor = executor;
|
|
148
160
|
}
|
|
161
|
+
/** Inject WeChat contact binding-code executor. */
|
|
162
|
+
setWechatContactBindExecutor(executor) {
|
|
163
|
+
this.wechatContactBindExecutor = executor;
|
|
164
|
+
}
|
|
149
165
|
/** Start the 1s background CPU sampling loop (for monitor-snapshot). Call after start(). */
|
|
150
166
|
startCpuTracking() {
|
|
151
167
|
if (this.cpuTimer)
|
|
@@ -325,22 +341,72 @@ export class IpcServer {
|
|
|
325
341
|
if (!this.dingtalkContactBindExecutor) {
|
|
326
342
|
return { ok: false, error: 'dingtalk contact bind executor not configured' };
|
|
327
343
|
}
|
|
344
|
+
if (this.dingtalkContactBindExecutor.isChannelReady
|
|
345
|
+
&& !this.dingtalkContactBindExecutor.isChannelReady(cmd.channelName)) {
|
|
346
|
+
return { ok: false, error: 'channel instance is not connected' };
|
|
347
|
+
}
|
|
328
348
|
return this.dingtalkContactBindExecutor.register({
|
|
329
349
|
selfAid: cmd.selfAid,
|
|
330
350
|
channelName: cmd.channelName,
|
|
331
351
|
primaryId: cmd.primaryId,
|
|
332
352
|
});
|
|
333
353
|
}
|
|
354
|
+
case 'feishu.contact-bind.register': {
|
|
355
|
+
if (!this.feishuContactBindExecutor) {
|
|
356
|
+
return { ok: false, error: 'feishu contact bind executor not configured' };
|
|
357
|
+
}
|
|
358
|
+
if (this.feishuContactBindExecutor.isChannelReady
|
|
359
|
+
&& !this.feishuContactBindExecutor.isChannelReady(cmd.channelName)) {
|
|
360
|
+
return { ok: false, error: 'channel instance is not connected' };
|
|
361
|
+
}
|
|
362
|
+
return this.feishuContactBindExecutor.register({
|
|
363
|
+
selfAid: cmd.selfAid,
|
|
364
|
+
channelName: cmd.channelName,
|
|
365
|
+
primaryId: cmd.primaryId,
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
case 'qqbot.contact-bind.register': {
|
|
369
|
+
if (!this.qqbotContactBindExecutor) {
|
|
370
|
+
return { ok: false, error: 'qqbot contact bind executor not configured' };
|
|
371
|
+
}
|
|
372
|
+
if (this.qqbotContactBindExecutor.isChannelReady
|
|
373
|
+
&& !this.qqbotContactBindExecutor.isChannelReady(cmd.channelName)) {
|
|
374
|
+
return { ok: false, error: 'channel instance is not connected' };
|
|
375
|
+
}
|
|
376
|
+
return this.qqbotContactBindExecutor.register({
|
|
377
|
+
selfAid: cmd.selfAid,
|
|
378
|
+
channelName: cmd.channelName,
|
|
379
|
+
primaryId: cmd.primaryId,
|
|
380
|
+
});
|
|
381
|
+
}
|
|
334
382
|
case 'wecom.contact-bind.register': {
|
|
335
383
|
if (!this.wecomContactBindExecutor) {
|
|
336
384
|
return { ok: false, error: 'wecom contact bind executor not configured' };
|
|
337
385
|
}
|
|
386
|
+
if (this.wecomContactBindExecutor.isChannelReady
|
|
387
|
+
&& !this.wecomContactBindExecutor.isChannelReady(cmd.channelName)) {
|
|
388
|
+
return { ok: false, error: 'channel instance is not connected' };
|
|
389
|
+
}
|
|
338
390
|
return this.wecomContactBindExecutor.register({
|
|
339
391
|
selfAid: cmd.selfAid,
|
|
340
392
|
channelName: cmd.channelName,
|
|
341
393
|
primaryId: cmd.primaryId,
|
|
342
394
|
});
|
|
343
395
|
}
|
|
396
|
+
case 'wechat.contact-bind.register': {
|
|
397
|
+
if (!this.wechatContactBindExecutor) {
|
|
398
|
+
return { ok: false, error: 'wechat contact bind executor not configured' };
|
|
399
|
+
}
|
|
400
|
+
if (this.wechatContactBindExecutor.isChannelReady
|
|
401
|
+
&& !this.wechatContactBindExecutor.isChannelReady(cmd.channelName)) {
|
|
402
|
+
return { ok: false, error: 'channel instance is not connected' };
|
|
403
|
+
}
|
|
404
|
+
return this.wechatContactBindExecutor.register({
|
|
405
|
+
selfAid: cmd.selfAid,
|
|
406
|
+
channelName: cmd.channelName,
|
|
407
|
+
primaryId: cmd.primaryId,
|
|
408
|
+
});
|
|
409
|
+
}
|
|
344
410
|
case 'aun-aids': {
|
|
345
411
|
const aids = this.aunAidProvider ? this.aunAidProvider() : [];
|
|
346
412
|
return { ok: true, aids };
|
|
@@ -457,6 +523,7 @@ export class IpcServer {
|
|
|
457
523
|
originSessionId: typeof cmd.originSessionId === 'string' ? cmd.originSessionId : undefined,
|
|
458
524
|
originMessageId: typeof cmd.originMessageId === 'string' ? cmd.originMessageId : undefined,
|
|
459
525
|
delegationToken: typeof cmd.delegationToken === 'string' ? cmd.delegationToken : undefined,
|
|
526
|
+
delegationCommandHash: typeof cmd.delegationCommandHash === 'string' ? cmd.delegationCommandHash : undefined,
|
|
460
527
|
log,
|
|
461
528
|
});
|
|
462
529
|
}
|
|
@@ -475,6 +542,7 @@ export class IpcServer {
|
|
|
475
542
|
handoffId: typeof cmd.handoffId === 'string' ? cmd.handoffId : undefined,
|
|
476
543
|
content: cmd.content,
|
|
477
544
|
delegationToken: typeof cmd.delegationToken === 'string' ? cmd.delegationToken : undefined,
|
|
545
|
+
delegationCommandHash: typeof cmd.delegationCommandHash === 'string' ? cmd.delegationCommandHash : undefined,
|
|
478
546
|
});
|
|
479
547
|
}
|
|
480
548
|
catch (e) {
|
|
@@ -533,7 +601,7 @@ export class IpcServer {
|
|
|
533
601
|
const { cmd: slashCmd, sessionId } = cmd;
|
|
534
602
|
if (!slashCmd || !sessionId)
|
|
535
603
|
return { ok: false, error: 'missing cmd or sessionId' };
|
|
536
|
-
return await this.commandExecutor(slashCmd, sessionId, typeof cmd.delegationToken === 'string' ? cmd.delegationToken : undefined);
|
|
604
|
+
return await this.commandExecutor(slashCmd, sessionId, typeof cmd.delegationToken === 'string' ? cmd.delegationToken : undefined, typeof cmd.delegationCommandHash === 'string' ? cmd.delegationCommandHash : undefined);
|
|
537
605
|
}
|
|
538
606
|
case 'config.op': {
|
|
539
607
|
if (!this.configOperationExecutor)
|
|
@@ -545,7 +613,7 @@ export class IpcServer {
|
|
|
545
613
|
if (delegationToken !== undefined && typeof delegationToken !== 'string') {
|
|
546
614
|
return { ok: false, code: 'INVALID_DELEGATION', error: 'delegationToken must be a string' };
|
|
547
615
|
}
|
|
548
|
-
return await this.configOperationExecutor(argv, sessionId, delegationToken);
|
|
616
|
+
return await this.configOperationExecutor(argv, sessionId, delegationToken, typeof cmd.delegationCommandHash === 'string' ? cmd.delegationCommandHash : undefined);
|
|
549
617
|
}
|
|
550
618
|
case 'contact.op': {
|
|
551
619
|
if (!this.contactOperationExecutor)
|
|
@@ -557,7 +625,7 @@ export class IpcServer {
|
|
|
557
625
|
if (delegationToken !== undefined && typeof delegationToken !== 'string') {
|
|
558
626
|
return { ok: false, code: 'INVALID_DELEGATION', error: 'delegationToken must be a string' };
|
|
559
627
|
}
|
|
560
|
-
return await this.contactOperationExecutor(argv, sessionId, delegationToken);
|
|
628
|
+
return await this.contactOperationExecutor(argv, sessionId, delegationToken, typeof cmd.delegationCommandHash === 'string' ? cmd.delegationCommandHash : undefined);
|
|
561
629
|
}
|
|
562
630
|
case 'trigger.list':
|
|
563
631
|
case 'trigger.show':
|
|
@@ -613,6 +681,10 @@ export class IpcServer {
|
|
|
613
681
|
return { ok: false, error: `Agent "${name}" not found` };
|
|
614
682
|
if (!this.agentRegistry.reload)
|
|
615
683
|
return { ok: false, error: 'EvolAgentRegistry.reload not available' };
|
|
684
|
+
// 'kits' 组(manifest / fragment / schema / 角色模板)走 on-reload 策略,平时不查盘:
|
|
685
|
+
// reload 是它唯一的刷新时机,必须先清再 reload,否则重载出来的 agent 仍用旧模板。
|
|
686
|
+
const { invalidateKitCache } = await import('./eck/kit-renderer.js');
|
|
687
|
+
invalidateKitCache();
|
|
616
688
|
await this.agentRegistry.reload(name, hooks);
|
|
617
689
|
return { ok: true, result: `Agent "${name}" reloaded` };
|
|
618
690
|
}
|
|
@@ -745,6 +817,11 @@ export class IpcServer {
|
|
|
745
817
|
* Returns null if the service is not running or the socket is unreachable.
|
|
746
818
|
*/
|
|
747
819
|
export function ipcQuery(socketPath, cmd, timeoutMs = 3000) {
|
|
820
|
+
const delegationCommandHash = typeof cmd.delegationToken === 'string'
|
|
821
|
+
&& typeof cmd.delegationCommandHash !== 'string'
|
|
822
|
+
? hashCurrentDelegatedCommand()
|
|
823
|
+
: undefined;
|
|
824
|
+
const request = delegationCommandHash ? { ...cmd, delegationCommandHash } : cmd;
|
|
748
825
|
return new Promise((resolve) => {
|
|
749
826
|
const conn = net.connect(socketPath);
|
|
750
827
|
let buf = '';
|
|
@@ -753,7 +830,7 @@ export function ipcQuery(socketPath, cmd, timeoutMs = 3000) {
|
|
|
753
830
|
resolve(null);
|
|
754
831
|
}, timeoutMs);
|
|
755
832
|
conn.on('connect', () => {
|
|
756
|
-
conn.write(JSON.stringify(
|
|
833
|
+
conn.write(JSON.stringify(request) + '\n');
|
|
757
834
|
});
|
|
758
835
|
conn.on('data', (data) => {
|
|
759
836
|
buf += data.toString();
|
package/dist/paths.js
CHANGED
|
@@ -86,6 +86,9 @@ export function agentConfig(aid) {
|
|
|
86
86
|
export function agentContactConfig(aid) {
|
|
87
87
|
return path.join(agentDir(aid), 'contact.json');
|
|
88
88
|
}
|
|
89
|
+
export function agentContactOperations(aid) {
|
|
90
|
+
return path.join(agentDir(aid), 'contact-operations.jsonl');
|
|
91
|
+
}
|
|
89
92
|
export function agentPersonalDir(aid) {
|
|
90
93
|
return path.join(agentDir(aid), 'personal');
|
|
91
94
|
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { ResponseModeResolver } from './resolver.js';
|
|
2
|
+
/** Extract mode-specific factory defaults from the registered mode schema. */
|
|
3
|
+
export function responseModeSchemaDefaults(mode) {
|
|
4
|
+
const properties = mode.configSchema?.properties;
|
|
5
|
+
if (!properties)
|
|
6
|
+
return {};
|
|
7
|
+
const defaults = {};
|
|
8
|
+
for (const [key, spec] of Object.entries(properties)) {
|
|
9
|
+
if (spec && typeof spec === 'object' && 'default' in spec) {
|
|
10
|
+
defaults[key] = spec.default;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
return defaults;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Resolve the selected mode and assemble its effective parameter bucket.
|
|
17
|
+
* Response processing and pre-processing consumers such as Session Renew must
|
|
18
|
+
* share this function so they cannot select different mode configurations.
|
|
19
|
+
*/
|
|
20
|
+
export function resolveEffectiveResponseModeConfig(registry, config, resolvedChatMode) {
|
|
21
|
+
const resolved = new ResponseModeResolver(registry).resolve(config.responseMode);
|
|
22
|
+
const modeSpecificParams = config.responseModeParams?.[resolved.mode.id] ?? {};
|
|
23
|
+
const modeConfig = {
|
|
24
|
+
...responseModeSchemaDefaults(resolved.mode),
|
|
25
|
+
...(resolvedChatMode !== undefined ? { chatmode: resolvedChatMode } : {}),
|
|
26
|
+
...modeSpecificParams,
|
|
27
|
+
};
|
|
28
|
+
return { ...resolved, modeConfig };
|
|
29
|
+
}
|
|
@@ -13,33 +13,13 @@
|
|
|
13
13
|
* - 响应模式成为「响应决策的源头」,下游 message-processor 的执行流程原样保留
|
|
14
14
|
* - 异常不降级(D6):解析/决策失败时回落到安全默认,记 WARN
|
|
15
15
|
*/
|
|
16
|
-
import { ResponseModeResolver } from './resolver.js';
|
|
17
16
|
import { ResponseModeContextBuilder } from './context-builder.js';
|
|
18
|
-
|
|
19
|
-
* 从模式的 configSchema 提取特有参数出厂默认值:`properties[key].default`。
|
|
20
|
-
*
|
|
21
|
-
* 模式 schema 是模式特有参数「候选值 + 默认值」的唯一事实源(architecture §五)。
|
|
22
|
-
* 宿主组装 modeConfig 时先铺这层默认,再叠用户显式配置——默认来源收敛到 schema,
|
|
23
|
-
* flow 不再硬编码 `?? true` 之类的默认。chatMode 无 default(宿主强制注入),跳过。
|
|
24
|
-
*/
|
|
25
|
-
function schemaDefaults(mode) {
|
|
26
|
-
const props = mode.configSchema?.properties;
|
|
27
|
-
if (!props)
|
|
28
|
-
return {};
|
|
29
|
-
const out = {};
|
|
30
|
-
for (const [key, spec] of Object.entries(props)) {
|
|
31
|
-
if (spec && typeof spec === 'object' && 'default' in spec)
|
|
32
|
-
out[key] = spec.default;
|
|
33
|
-
}
|
|
34
|
-
return out;
|
|
35
|
-
}
|
|
17
|
+
import { resolveEffectiveResponseModeConfig } from './config-resolver.js';
|
|
36
18
|
export class ResponseModeCoordinator {
|
|
37
19
|
registry;
|
|
38
|
-
resolver;
|
|
39
20
|
contextBuilder = new ResponseModeContextBuilder();
|
|
40
21
|
constructor(registry) {
|
|
41
22
|
this.registry = registry;
|
|
42
|
-
this.resolver = new ResponseModeResolver(registry);
|
|
43
23
|
}
|
|
44
24
|
/**
|
|
45
25
|
* 解析会话该用哪个响应模式 + 构建 context(不调 handleInbound)。
|
|
@@ -54,12 +34,11 @@ export class ResponseModeCoordinator {
|
|
|
54
34
|
*/
|
|
55
35
|
resolveMode(responseModeId, resolvedChatMode, responseModeParams, contextDeps) {
|
|
56
36
|
try {
|
|
57
|
-
const resolved = this.
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
const
|
|
62
|
-
const modeConfig = { ...schemaDefaults(mode), chatmode: resolvedChatMode, ...modeSpecificParams };
|
|
37
|
+
const resolved = resolveEffectiveResponseModeConfig(this.registry, {
|
|
38
|
+
responseMode: responseModeId,
|
|
39
|
+
responseModeParams,
|
|
40
|
+
}, resolvedChatMode);
|
|
41
|
+
const { mode, modeConfig } = resolved;
|
|
63
42
|
contextDeps.logger.debug('[ResponseSystem] resolveMode mode=' + mode.id + ' source=' + resolved.source + ' chatmode=' + (modeConfig.chatmode ?? 'none'));
|
|
64
43
|
const context = this.contextBuilder.build(mode.id, { ...contextDeps, modeConfig });
|
|
65
44
|
return { mode, context, source: resolved.source };
|
|
@@ -78,11 +57,8 @@ export class ResponseModeCoordinator {
|
|
|
78
57
|
async resolveInbound(message, deps, resolvedChatMode) {
|
|
79
58
|
try {
|
|
80
59
|
// 解析模式:标量 responseMode(合并后)> 注册表首选。chatMode 不参与选模式。
|
|
81
|
-
const resolved = this.
|
|
82
|
-
const mode = resolved
|
|
83
|
-
// 先铺 schema 出厂默认,再叠用户显式桶(显式值优先),chatmode 强制注入。
|
|
84
|
-
const modeSpecificParams = deps.agentConfig.responseModeParams?.[mode.id] ?? {};
|
|
85
|
-
const modeConfig = { ...schemaDefaults(mode), chatmode: resolvedChatMode, ...modeSpecificParams };
|
|
60
|
+
const resolved = resolveEffectiveResponseModeConfig(this.registry, deps.agentConfig, resolvedChatMode);
|
|
61
|
+
const { mode, modeConfig } = resolved;
|
|
86
62
|
deps.contextDeps.logger.debug('[ResponseSystem] resolveInbound mode=' + mode.id + ' source=' + resolved.source + ' chatmode=' + (modeConfig.chatmode ?? 'none'));
|
|
87
63
|
const context = this.contextBuilder.build(mode.id, {
|
|
88
64
|
...deps.contextDeps,
|
|
@@ -19,7 +19,7 @@ function isHumanFacingMessage(message) {
|
|
|
19
19
|
}
|
|
20
20
|
function buildState(message, cfg) {
|
|
21
21
|
// 默认值不在此硬编码:候选/出厂默认由模式 schema 声明,宿主组装 modeConfig 时注入
|
|
22
|
-
// (
|
|
22
|
+
// (responseModeSchemaDefaults)。此处只读注入后的布尔——键缺失即视为关闭。
|
|
23
23
|
const preTool1stMsgChk = cfg.pre_tool_1stmsgchk === true;
|
|
24
24
|
const toolUseReminder = cfg.tool_use_reminder === true;
|
|
25
25
|
const humanFacing = isHumanFacingMessage(message);
|
|
@@ -2,12 +2,15 @@ import { FIFOQueue } from '../../queues/fifo-queue.js';
|
|
|
2
2
|
import { flowForChatMode } from '../../engines/v1/index.js';
|
|
3
3
|
import { loadSchema } from '../../../config/schema-registry.js';
|
|
4
4
|
/**
|
|
5
|
-
* 模式桶 schema ——
|
|
5
|
+
* 模式桶 schema —— 候选值与默认值的**唯一事实源**,从当前 single-session schema
|
|
6
6
|
* 读取(随包分发、config schema 子命令可展示、write 时桶专项校验共用同一份)。
|
|
7
|
-
* `default`
|
|
7
|
+
* `default` 即运行时出厂默认,由共享 config resolver 组装 modeConfig 时提取注入,
|
|
8
8
|
* flow 不再硬编码默认。chatMode 无 default——由宿主按 chatmode 场景表解析后强制注入。
|
|
9
|
+
*
|
|
10
|
+
* 每次现取而非模块初始化时定格:`loadSchema` 自己走 FileCache(读是缓存命中),
|
|
11
|
+
* 定格反而会绕过 invalidateKitCache——schema 改了、registry 已换新,本模式却仍
|
|
12
|
+
* 用旧默认值。
|
|
9
13
|
*/
|
|
10
|
-
const CONFIG_SCHEMA = loadSchema('single-session').raw;
|
|
11
14
|
/**
|
|
12
15
|
* 单会话响应模式(architecture.md §4.1)—— 合并原 interactive / proactive。
|
|
13
16
|
*
|
|
@@ -21,7 +24,7 @@ export class SingleSessionMode {
|
|
|
21
24
|
description = '单会话直接响应,按 chatMode 决定投递方式。';
|
|
22
25
|
type = 'builtin';
|
|
23
26
|
applicableScenes = ['private', 'group'];
|
|
24
|
-
configSchema
|
|
27
|
+
get configSchema() { return loadSchema('single-session').raw; }
|
|
25
28
|
queue = new FIFOQueue();
|
|
26
29
|
context;
|
|
27
30
|
async initialize(context) {
|
package/dist/trigger/parser.js
CHANGED
|
@@ -27,6 +27,34 @@ function parseFlags(args) {
|
|
|
27
27
|
}
|
|
28
28
|
return flags;
|
|
29
29
|
}
|
|
30
|
+
function promptSyntaxError(args) {
|
|
31
|
+
const match = /--prompt(?:\s+|=|$)/.exec(args);
|
|
32
|
+
if (!match)
|
|
33
|
+
return undefined;
|
|
34
|
+
const rest = args.slice((match.index ?? 0) + match[0].length).trimStart();
|
|
35
|
+
const quote = rest[0];
|
|
36
|
+
if (quote !== '"' && quote !== "'")
|
|
37
|
+
return undefined;
|
|
38
|
+
for (let index = 1; index < rest.length; index++) {
|
|
39
|
+
if (rest[index] === '\\') {
|
|
40
|
+
index += 1;
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
if (rest[index] === quote)
|
|
44
|
+
return undefined;
|
|
45
|
+
}
|
|
46
|
+
return '--prompt 引号未闭合;复杂内容建议改用 --prompt-file <path>';
|
|
47
|
+
}
|
|
48
|
+
function inlinePromptPresent(args) {
|
|
49
|
+
if (Array.isArray(args))
|
|
50
|
+
return args.some(arg => arg === '--prompt' || arg.startsWith('--prompt='));
|
|
51
|
+
return /--prompt(?:\s+|=|$)/.test(args);
|
|
52
|
+
}
|
|
53
|
+
function withPromptFileHint(error, args, opts = {}) {
|
|
54
|
+
if (!inlinePromptPresent(args) || opts.allowLongPrompt || error.includes('--prompt-file'))
|
|
55
|
+
return error;
|
|
56
|
+
return `${error};复杂内容建议改用 --prompt-file <path>`;
|
|
57
|
+
}
|
|
30
58
|
export function parseDuration(s) {
|
|
31
59
|
const m = /^([1-9]\d*)([dhms])$/.exec(s.trim().toLowerCase());
|
|
32
60
|
if (!m)
|
|
@@ -326,9 +354,10 @@ function commonParsed(flags, opts = {}) {
|
|
|
326
354
|
}
|
|
327
355
|
const prompt = flags.get('prompt');
|
|
328
356
|
if (prompt === true)
|
|
329
|
-
return { ok: false, error: '--prompt
|
|
330
|
-
if (typeof prompt === 'string' && prompt.length > 4096)
|
|
331
|
-
return { ok: false, error: '--prompt 超过 4096
|
|
357
|
+
return { ok: false, error: '--prompt 不能为空;复杂内容建议改用 --prompt-file <path>' };
|
|
358
|
+
if (typeof prompt === 'string' && prompt.length > 4096 && !opts.allowLongPrompt) {
|
|
359
|
+
return { ok: false, error: '--prompt 超过 4096 字符限制;复杂内容建议改用 --prompt-file <path>' };
|
|
360
|
+
}
|
|
332
361
|
const scriptPath = flags.get('script-path');
|
|
333
362
|
if (scriptPath === true)
|
|
334
363
|
return { ok: false, error: '--script-path 不能为空' };
|
|
@@ -351,7 +380,10 @@ function commonParsed(flags, opts = {}) {
|
|
|
351
380
|
if ((targetChannel === undefined) !== (targetChannelId === undefined)) {
|
|
352
381
|
return { ok: false, error: '--target-channel 与 --target-channel-id 必须同时指定或同时省略' };
|
|
353
382
|
}
|
|
354
|
-
|
|
383
|
+
if (!opts.update && !execution.value) {
|
|
384
|
+
return { ok: false, error: '创建 trigger 必须显式指定 --exec script|trigger-session|target-session' };
|
|
385
|
+
}
|
|
386
|
+
const inferredExecution = execution.value;
|
|
355
387
|
if (baseagent.value && inferredExecution !== 'trigger_session') {
|
|
356
388
|
return { ok: false, error: '--baseagent 仅适用于 --exec trigger-session' };
|
|
357
389
|
}
|
|
@@ -395,10 +427,13 @@ function commonParsed(flags, opts = {}) {
|
|
|
395
427
|
};
|
|
396
428
|
}
|
|
397
429
|
export function parseTriggerSet(args) {
|
|
430
|
+
const syntaxError = promptSyntaxError(args);
|
|
431
|
+
if (syntaxError)
|
|
432
|
+
return { ok: false, error: syntaxError };
|
|
398
433
|
const flags = parseFlags(args);
|
|
399
434
|
const parsed = commonParsed(flags);
|
|
400
435
|
if (!parsed.ok)
|
|
401
|
-
return parsed;
|
|
436
|
+
return { ok: false, error: withPromptFileHint(parsed.error, args) };
|
|
402
437
|
const value = parsed.value;
|
|
403
438
|
return {
|
|
404
439
|
ok: true,
|
|
@@ -431,13 +466,13 @@ export function parseTriggerSet(args) {
|
|
|
431
466
|
}
|
|
432
467
|
/** CLI argv parser. Unlike the slash-command string parser, this preserves
|
|
433
468
|
* shell-quoted values such as `--prompt "multi word text"` as one token. */
|
|
434
|
-
export function parseTriggerSetArgv(args) {
|
|
469
|
+
export function parseTriggerSetArgv(args, opts = {}) {
|
|
435
470
|
const parsedFlags = flagsFromArgv(args, 'create');
|
|
436
471
|
if (!parsedFlags.ok)
|
|
437
|
-
return parsedFlags;
|
|
438
|
-
const parsed = commonParsed(parsedFlags.flags);
|
|
472
|
+
return { ok: false, error: withPromptFileHint(parsedFlags.error, args, opts) };
|
|
473
|
+
const parsed = commonParsed(parsedFlags.flags, opts);
|
|
439
474
|
if (!parsed.ok)
|
|
440
|
-
return parsed;
|
|
475
|
+
return { ok: false, error: withPromptFileHint(parsed.error, args, opts) };
|
|
441
476
|
const value = parsed.value;
|
|
442
477
|
return {
|
|
443
478
|
ok: true,
|
|
@@ -491,14 +526,19 @@ export function parseTriggerUpdate(args) {
|
|
|
491
526
|
}
|
|
492
527
|
if (!rest)
|
|
493
528
|
return { ok: false, error: '至少需要指定一个修改参数(如 --prompt、--delay、--event 等)' };
|
|
529
|
+
const syntaxError = promptSyntaxError(rest);
|
|
530
|
+
if (syntaxError)
|
|
531
|
+
return { ok: false, error: syntaxError };
|
|
494
532
|
const flags = parseFlags(rest);
|
|
495
|
-
|
|
533
|
+
const parsed = parseTriggerUpdateFlags(nameOrId, flags);
|
|
534
|
+
return parsed.ok ? parsed : { ok: false, error: withPromptFileHint(parsed.error, rest) };
|
|
496
535
|
}
|
|
497
|
-
export function parseTriggerUpdateArgv(nameOrId, args) {
|
|
536
|
+
export function parseTriggerUpdateArgv(nameOrId, args, opts = {}) {
|
|
498
537
|
const parsedFlags = flagsFromArgv(args, 'update');
|
|
499
538
|
if (!parsedFlags.ok)
|
|
500
|
-
return parsedFlags;
|
|
501
|
-
|
|
539
|
+
return { ok: false, error: withPromptFileHint(parsedFlags.error, args, opts) };
|
|
540
|
+
const parsed = parseTriggerUpdateFlags(nameOrId, parsedFlags.flags, opts);
|
|
541
|
+
return parsed.ok ? parsed : { ok: false, error: withPromptFileHint(parsed.error, args, opts) };
|
|
502
542
|
}
|
|
503
543
|
function flagsFromArgv(args, command) {
|
|
504
544
|
const flags = new Map();
|
|
@@ -523,14 +563,14 @@ function flagsFromArgv(args, command) {
|
|
|
523
563
|
}
|
|
524
564
|
return { ok: true, flags };
|
|
525
565
|
}
|
|
526
|
-
function parseTriggerUpdateFlags(nameOrId, flags) {
|
|
566
|
+
function parseTriggerUpdateFlags(nameOrId, flags, opts = {}) {
|
|
527
567
|
if (flags.size === 0)
|
|
528
568
|
return { ok: false, error: '至少需要指定一个修改参数(如 --prompt、--delay、--event 等)' };
|
|
529
569
|
for (const flag of flags.keys()) {
|
|
530
570
|
if (!TRIGGER_UPDATE_FLAGS.has(flag))
|
|
531
571
|
return { ok: false, error: `update 不支持参数 --${flag}` };
|
|
532
572
|
}
|
|
533
|
-
const parsed = commonParsed(flags, { update: true });
|
|
573
|
+
const parsed = commonParsed(flags, { update: true, ...opts });
|
|
534
574
|
if (!parsed.ok)
|
|
535
575
|
return parsed;
|
|
536
576
|
const value = parsed.value;
|
package/dist/trigger/patch.js
CHANGED
|
@@ -13,7 +13,7 @@ const PATCH_KEYS = new Set([
|
|
|
13
13
|
'concurrency',
|
|
14
14
|
'missedPolicy',
|
|
15
15
|
]);
|
|
16
|
-
export function applyTriggerPatch(definition, input) {
|
|
16
|
+
export function applyTriggerPatch(definition, input, opts = {}) {
|
|
17
17
|
if (!input || typeof input !== 'object' || Array.isArray(input)) {
|
|
18
18
|
throw new Error('trigger patch must be an object');
|
|
19
19
|
}
|
|
@@ -30,6 +30,9 @@ export function applyTriggerPatch(definition, input) {
|
|
|
30
30
|
updated.name = String(patch.name);
|
|
31
31
|
applySourcePatch(updated, patch);
|
|
32
32
|
if (patch.prompt !== undefined) {
|
|
33
|
+
if (opts.fromPromptFile && updated.execution.type === 'script') {
|
|
34
|
+
throw new Error('script 类型 trigger 不支持 --prompt-file;请修改脚本文件后重新创建 trigger');
|
|
35
|
+
}
|
|
33
36
|
if (updated.execution.type === 'script')
|
|
34
37
|
updated.feedback.onReply = { template: String(patch.prompt) };
|
|
35
38
|
else
|