evolcore 0.0.23 → 0.0.25
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 +583 -516
- package/LICENSE +21 -21
- package/README.md +455 -453
- package/bin/codex-managed-acl.ps1 +160 -155
- package/bin/codex-managed-hook.mjs +209 -92
- package/bin/ec-safe-output.js +327 -245
- package/bin/ec.js +29 -29
- package/bin/install-codex-managed-hooks.mjs +555 -544
- package/dist/agents/baseagent-availability.js +4 -4
- package/dist/agents/baseagent.js +29 -1
- package/dist/agents/claude-runner.js +152 -14
- package/dist/agents/codex/app-server-client.js +18 -8
- package/dist/agents/codex/catalog.js +1 -1
- package/dist/agents/codex/diagnostics.js +215 -0
- package/dist/agents/codex-runner.js +445 -63
- package/dist/agents/ecagent-runner.js +31 -16
- package/dist/agents/gemini-runner.js +82 -4
- package/dist/agents/runner-types.js +1 -1
- package/dist/aun/aid/agentmd.js +56 -4
- package/dist/aun/aid/index.js +1 -0
- package/dist/aun/aid/managed-operation.js +80 -6
- package/dist/aun/aid/store.js +41 -0
- package/dist/aun/msg/managed-operation.js +6 -1
- package/dist/aun/outbox.js +56 -18
- package/dist/aun/rpc/client.js +4 -5
- package/dist/aun/storage/client.js +4 -1
- package/dist/aun/storage/index.js +1 -1
- package/dist/channels/aun.js +147 -76
- package/dist/channels/daemon.js +7 -1
- package/dist/channels/dingtalk.js +1 -0
- package/dist/channels/feishu.js +10 -4
- package/dist/channels/wecom.js +2 -1
- package/dist/cli/agent-command.js +214 -89
- package/dist/cli/agent-create.js +576 -0
- package/dist/cli/agent.js +129 -676
- package/dist/cli/aun-commands.js +419 -313
- package/dist/cli/bench.js +20 -20
- package/dist/cli/config.js +20 -20
- package/dist/cli/contact.js +10 -10
- package/dist/cli/ctl-command.js +22 -20
- package/dist/cli/daemon-commands.js +163 -32
- package/dist/cli/fs-command.js +67 -67
- package/dist/cli/handoff-command.js +7 -7
- package/dist/cli/index.js +79 -79
- package/dist/cli/link-rules.js +21 -21
- package/dist/cli/managed-command-guard.js +3 -0
- package/dist/cli/menu-client.js +11 -11
- package/dist/cli/net-check.js +22 -22
- package/dist/cli/queue-command.js +29 -29
- package/dist/cli/response.js +30 -30
- package/dist/cli/restart-monitor.js +462 -38
- package/dist/cli/stats.js +161 -51
- package/dist/cli/trigger-command.js +56 -56
- package/dist/config/builtin-roles.js +3 -0
- package/dist/config/config-manager.js +15 -0
- package/dist/config/config-operation-service.js +20 -3
- package/dist/config/resolved-config-op.js +39 -1
- package/dist/core/auth/auth-gateway.js +3 -2
- package/dist/core/auth/authorization-audit.js +72 -19
- package/dist/core/auth/operation-authorizer.js +125 -7
- package/dist/core/auth/operation-catalog.js +26 -2
- package/dist/core/auth/remote-access-store.js +3 -2
- package/dist/core/baseagent-loader.js +4 -4
- package/dist/core/bootstrap-messages.js +39 -18
- package/dist/core/bootstrap-service.js +32 -26
- package/dist/core/capability/capability-manager.js +8 -4
- package/dist/core/capability/providers/codex-capability-provider.js +1 -1
- package/dist/core/command/agent-control.js +60 -26
- package/dist/core/command/cli-intent-parser.js +18 -0
- package/dist/core/command/command-handler.js +173 -36
- package/dist/core/command/menu-catalog.js +4 -1
- package/dist/core/command/menu-handler.js +315 -75
- package/dist/core/command/menu-protocol.js +7 -2
- package/dist/core/command/slash-gate.js +1 -3
- package/dist/core/command/slash-handler.js +166 -57
- package/dist/core/data-migration.js +5 -15
- package/dist/core/event-catalog.js +8 -0
- package/dist/core/evolagent.js +3 -3
- package/dist/core/handoff/runtime.js +3 -1
- package/dist/core/handoff/store.js +7 -1
- package/dist/core/message/im-renderer.js +13 -6
- package/dist/core/message/message-bridge.js +5 -36
- package/dist/core/message/message-utils.js +6 -3
- package/dist/core/message/response-engine.js +85 -27
- package/dist/core/model/catalog-service.js +3 -1
- package/dist/core/model/model-catalog.js +10 -0
- package/dist/core/model/model-permission.js +4 -1
- package/dist/core/permission/approval-gateway.js +169 -33
- package/dist/core/permission/tool-policy.js +56 -10
- package/dist/core/session/adapters/codex-session-file-adapter.js +71 -3
- package/dist/core/session/session-manager.js +49 -13
- package/dist/core/session/session-renew.js +1 -0
- package/dist/index.js +327 -134
- package/dist/ipc.js +68 -21
- package/dist/paths.js +23 -1
- package/dist/stats/billing.js +18 -4
- package/dist/stats/db.js +159 -159
- package/dist/stats/eck-vars.js +9 -9
- package/dist/stats/query.js +139 -139
- package/dist/stats/role-budget.js +6 -6
- package/dist/stats/writer.js +51 -51
- package/dist/utils/atomic-write.js +26 -2
- package/dist/utils/avatar-upload.js +282 -23
- package/dist/utils/cross-platform.js +436 -1
- package/dist/utils/error-dict.json +160 -160
- package/dist/utils/error-utils.js +11 -4
- package/dist/utils/macos-autostart.js +22 -22
- package/dist/utils/model-prices.jsonl +23 -20
- package/dist/utils/npm-ops.js +24 -1
- package/dist/utils/welcome.js +22 -22
- package/dist/utils/windows-autostart.js +1 -1
- package/ecagent/LICENSE +21 -21
- package/ecagent/NOTICE +11 -11
- package/ecagent/README.md +61 -61
- package/ecagent/dist/harness/compaction/branch-summarization.js +30 -30
- package/ecagent/dist/harness/compaction/compaction.js +83 -83
- package/ecagent/dist/harness/messages.js +7 -7
- package/kits/docs/GUIDE.md +20 -20
- package/kits/docs/INDEX.md +66 -66
- package/kits/docs/aun/CHEATSHEET.md +19 -19
- package/kits/docs/aun/SYNC_PROTOCOL.md +15 -15
- package/kits/docs/channels/aun.md +56 -56
- package/kits/docs/channels/feishu.md +56 -56
- package/kits/docs/context-assembly.md +365 -364
- package/kits/docs/eck_templates/GUIDE.template.md +22 -22
- package/kits/docs/eck_templates/INDEX.template.md +28 -28
- package/kits/docs/eck_templates/path-registry.template.md +33 -33
- package/kits/docs/eck_templates/runtime.template.md +19 -19
- package/kits/docs/evolcore/INDEX.md +71 -69
- package/kits/docs/evolcore/agent-create.md +170 -156
- package/kits/docs/evolcore/agent.md +83 -73
- package/kits/docs/evolcore/aid.md +64 -62
- package/kits/docs/evolcore/codex-windows-sandbox.md +146 -0
- package/kits/docs/evolcore/config.md +195 -195
- package/kits/docs/evolcore/contact.md +68 -68
- package/kits/docs/evolcore/ctl.md +46 -46
- package/kits/docs/evolcore/event.md +216 -216
- package/kits/docs/evolcore/fs-architecture.md +1215 -1215
- package/kits/docs/evolcore/fs.md +110 -110
- package/kits/docs/evolcore/group-collaboration.md +243 -243
- package/kits/docs/evolcore/group-fs.md +17 -17
- package/kits/docs/evolcore/group-rules.md +251 -251
- package/kits/docs/evolcore/group.md +152 -152
- package/kits/docs/evolcore/menu-client.md +34 -34
- package/kits/docs/evolcore/model.md +50 -50
- package/kits/docs/evolcore/msg.md +165 -165
- package/kits/docs/evolcore/response.md +75 -75
- package/kits/docs/evolcore/rpc.md +37 -37
- package/kits/docs/evolcore/self-summary.md +29 -29
- package/kits/docs/evolcore/stats.md +83 -83
- package/kits/docs/evolcore/storage.md +50 -50
- package/kits/docs/evolcore/trigger.md +575 -575
- package/kits/docs/identity/AID_PROFILE_SPEC.md +26 -26
- package/kits/docs/identity/PATH_OPS.md +16 -16
- package/kits/docs/identity/ROLE_DETAIL.md +25 -25
- package/kits/docs/identity/identity-tools.md +26 -26
- package/kits/docs/path-registry.md +62 -62
- package/kits/docs/prompt-loading-architecture.md +270 -269
- package/kits/docs/venues/aun-group.md +45 -45
- package/kits/docs/venues/aun-private.md +10 -10
- package/kits/docs/venues/client-desktop.md +10 -10
- package/kits/docs/venues/client-mobile.md +10 -10
- package/kits/docs/venues/feishu-group.md +13 -13
- package/kits/docs/venues/feishu-private.md +9 -9
- package/kits/docs/venues/group.md +25 -25
- package/kits/docs/venues/private.md +10 -10
- package/kits/eck_manifest.auxiliary.json +43 -43
- package/kits/eck_manifest.json +195 -183
- package/kits/eck_message_manifest.json +74 -74
- package/kits/migrations/README-role-config-v4.md +32 -32
- package/kits/migrations/migrate-contact-book-v2.mjs +748 -748
- package/kits/migrations/migrate-role-config-v4.mjs +614 -614
- package/kits/migrations/migrate-role-config-v5.mjs +365 -365
- package/kits/migrations/rename-config-file.mjs +99 -99
- package/kits/rules/01-overview.md +162 -162
- package/kits/rules/02-navigation.md +96 -96
- package/kits/rules/03-identity.md +39 -37
- package/kits/rules/04-relation.md +75 -75
- package/kits/rules/05-venue.md +60 -60
- package/kits/rules/06-channel.md +63 -63
- package/kits/schemas/_meta.json +53 -53
- package/kits/schemas/agent-config.schema.1.json +177 -177
- package/kits/schemas/agent-config.schema.10.json +395 -395
- package/kits/schemas/agent-config.schema.11.json +421 -421
- package/kits/schemas/agent-config.schema.12.json +427 -427
- package/kits/schemas/agent-config.schema.2.json +239 -239
- package/kits/schemas/agent-config.schema.3.json +119 -119
- package/kits/schemas/agent-config.schema.4.json +208 -208
- package/kits/schemas/agent-config.schema.5.json +326 -326
- package/kits/schemas/agent-config.schema.6.json +322 -322
- package/kits/schemas/agent-config.schema.7.json +303 -303
- package/kits/schemas/agent-config.schema.8.json +304 -304
- package/kits/schemas/agent-config.schema.9.json +364 -364
- package/kits/schemas/contact-book.schema.1.json +36 -36
- package/kits/schemas/contact-book.schema.2.json +43 -43
- package/kits/schemas/contact-book.schema.3.json +67 -67
- package/kits/schemas/daemon.schema.1.json +91 -91
- package/kits/schemas/daemon.schema.2.json +101 -101
- package/kits/schemas/daemon.schema.3.json +123 -123
- package/kits/schemas/daemon.schema.4.json +136 -136
- package/kits/schemas/daemon.schema.5.json +135 -135
- package/kits/schemas/daemon.schema.6.json +131 -131
- package/kits/schemas/defaults.schema.1.json +81 -81
- package/kits/schemas/defaults.schema.2.json +85 -85
- package/kits/schemas/defaults.schema.3.json +73 -73
- package/kits/schemas/defaults.schema.4.json +107 -107
- package/kits/schemas/defaults.schema.5.json +119 -119
- package/kits/schemas/menu-exec-schema-commands.md +208 -208
- package/kits/schemas/migrations/README.md +30 -30
- package/kits/schemas/relation-config.schema.1.json +158 -158
- package/kits/schemas/relation-config.schema.2.json +73 -73
- package/kits/schemas/relation-config.schema.3.json +50 -50
- package/kits/schemas/relation-config.schema.4.json +47 -47
- package/kits/schemas/relation-config.schema.5.json +47 -47
- package/kits/schemas/relation-config.schema.6.json +46 -46
- package/kits/schemas/relation-config.schema.7.json +59 -59
- package/kits/schemas/relation-config.schema.8.json +103 -103
- package/kits/schemas/role-config.schema.1.json +201 -201
- package/kits/schemas/role-registry.schema.1.json +35 -35
- package/kits/schemas/single-session.schema.1.json +31 -31
- package/kits/schemas/single-session.schema.2.json +57 -57
- package/kits/schemas/single-session.schema.3.json +32 -32
- package/kits/templates/bootstrap-welcome.md +17 -17
- package/kits/templates/message-fragments/handoff-context-to-target.md +9 -9
- package/kits/templates/message-fragments/handoff-request-to-target.md +19 -19
- package/kits/templates/message-fragments/handoff-response-to-origin.md +9 -9
- package/kits/templates/message-fragments/inject-default.md +2 -2
- package/kits/templates/message-fragments/item.md +2 -2
- package/kits/templates/roles/admin.json +96 -82
- package/kits/templates/roles/member.json +97 -96
- package/kits/templates/roles/owner.json +9 -9
- package/kits/templates/roles/visitor.json +86 -85
- package/kits/templates/system-fragments/baseagent.md +14 -14
- package/kits/templates/system-fragments/bootstrap.md +38 -29
- package/kits/templates/system-fragments/channel.md +64 -64
- package/kits/templates/system-fragments/commands.md +28 -28
- package/kits/templates/system-fragments/identity.md +13 -13
- package/kits/templates/system-fragments/relation.md +19 -19
- package/kits/templates/system-fragments/session.md +59 -59
- package/kits/templates/system-fragments/venue.md +31 -31
- package/package.json +98 -94
- package/AGENTS.md +0 -62
- package/dist/utils/codex-cli.js +0 -43
- package/skills/eclink/SKILL.md +0 -84
- package/skills/eclink/agents/openai.yaml +0 -4
|
@@ -680,40 +680,6 @@ export class MessageBridge {
|
|
|
680
680
|
}
|
|
681
681
|
return d;
|
|
682
682
|
}
|
|
683
|
-
availableBaseagentsFor(channelName) {
|
|
684
|
-
const owningAgent = this.agentRegistry?.resolveByChannel(channelName);
|
|
685
|
-
if (!owningAgent)
|
|
686
|
-
return [];
|
|
687
|
-
const prefix = `${owningAgent.name}::`;
|
|
688
|
-
return this.processor.getAvailableAgents()
|
|
689
|
-
.filter(key => key.startsWith(prefix))
|
|
690
|
-
.map(key => key.slice(prefix.length));
|
|
691
|
-
}
|
|
692
|
-
async alignSessionBaseagent(channelName, session) {
|
|
693
|
-
const owningAgent = this.agentRegistry?.resolveByChannel(channelName);
|
|
694
|
-
if (!owningAgent)
|
|
695
|
-
return session;
|
|
696
|
-
const available = this.availableBaseagentsFor(channelName);
|
|
697
|
-
if (available.length === 0 || available.includes(session.baseagent))
|
|
698
|
-
return session;
|
|
699
|
-
// A topic's backend binding is fenced by SessionManager and cannot be
|
|
700
|
-
// cleared as a side effect of routing alignment. Reassigning the
|
|
701
|
-
// baseagent while leaving the old provider's agentSessionId persisted
|
|
702
|
-
// would make the new runner resume an incompatible backend. Keep the
|
|
703
|
-
// binding intact and let normal baseagent-mismatch handling report it;
|
|
704
|
-
// an explicit boundary operation must perform any future migration.
|
|
705
|
-
if (session.threadId) {
|
|
706
|
-
logger.error(`[MessageBridge] Cannot align topic to another baseagent: `
|
|
707
|
-
+ `session=${session.id} thread=${session.threadId} current=${session.baseagent} preferred=${owningAgent.baseagent}`);
|
|
708
|
-
return session;
|
|
709
|
-
}
|
|
710
|
-
const preferred = available.includes(owningAgent.baseagent)
|
|
711
|
-
? owningAgent.baseagent
|
|
712
|
-
: available[0];
|
|
713
|
-
logger.warn(`[MessageBridge] Aligning unavailable session baseagent: session=${session.id} ${session.baseagent} -> ${preferred} agent=${owningAgent.name} available=${available.join(',')}`);
|
|
714
|
-
await this.sessionManager.updateSession(session.id, { baseagent: preferred });
|
|
715
|
-
return { ...session, baseagent: preferred };
|
|
716
|
-
}
|
|
717
683
|
/**
|
|
718
684
|
* 为渠道注册消息桥梁:入站处理管线 + 出站命令响应
|
|
719
685
|
*
|
|
@@ -1140,7 +1106,6 @@ export class MessageBridge {
|
|
|
1140
1106
|
if (session.threadId && typeof this.messageQueue.reserveSessionIngress === 'function') {
|
|
1141
1107
|
releaseSessionIngress = this.messageQueue.reserveSessionIngress(session.id);
|
|
1142
1108
|
}
|
|
1143
|
-
session = await this.alignSessionBaseagent(channelName, session);
|
|
1144
1109
|
const replyToMessageId = typeof msg.replyContext?.metadata?.refMessageId === 'string'
|
|
1145
1110
|
? msg.replyContext.metadata.refMessageId
|
|
1146
1111
|
: msg.replyContext?.replyToMessageId ?? null;
|
|
@@ -1163,6 +1128,7 @@ export class MessageBridge {
|
|
|
1163
1128
|
content,
|
|
1164
1129
|
replyToMessageId,
|
|
1165
1130
|
isNewSession: !hadMainSession,
|
|
1131
|
+
currentBaseagent: owningAgent?.baseagent,
|
|
1166
1132
|
causation: inboundCausation,
|
|
1167
1133
|
});
|
|
1168
1134
|
session = renewResult.session;
|
|
@@ -1537,7 +1503,10 @@ export class MessageBridge {
|
|
|
1537
1503
|
channelId: msg.channelId,
|
|
1538
1504
|
args,
|
|
1539
1505
|
});
|
|
1540
|
-
const result = await this.cmdHandler.execMenuUpdate(this.resolveCmd(name, cmd), request.value, channel, execution.channelId, execution.subject.actorId, execution.subject.identity, execution.subject.fromControlChannel, execution.args, execution.subject
|
|
1506
|
+
const result = await this.cmdHandler.execMenuUpdate(this.resolveCmd(name, cmd), request.value, channel, execution.channelId, execution.subject.actorId, execution.subject.identity, execution.subject.fromControlChannel, execution.args, execution.subject, 'menu', {
|
|
1507
|
+
...(msg.replyContext ?? {}),
|
|
1508
|
+
...(msg.threadId ? { threadId: msg.threadId } : {}),
|
|
1509
|
+
});
|
|
1541
1510
|
if ('error' in result)
|
|
1542
1511
|
throw result;
|
|
1543
1512
|
return menuSuccess(header, result.data);
|
|
@@ -7,8 +7,9 @@ import { renderCommandCardAsText, renderActionAsText } from '../interaction-rout
|
|
|
7
7
|
/** A legacy adapter resolved its send call without providing a structured receipt. */
|
|
8
8
|
export const LEGACY_INTERACTION_ACCEPTED = 'legacy-accepted';
|
|
9
9
|
export function isInteractionSendAccepted(result) {
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
if (result === LEGACY_INTERACTION_ACCEPTED || result === 'sent')
|
|
11
|
+
return true;
|
|
12
|
+
return result !== false && (result.status === 'sent' || result.status === 'queued');
|
|
12
13
|
}
|
|
13
14
|
/**
|
|
14
15
|
* 构造出站消息信封
|
|
@@ -148,8 +149,10 @@ export async function sendInteractionPayload(adapter, envelope, interaction, fal
|
|
|
148
149
|
try {
|
|
149
150
|
const enriched = replyCtx ? withEnvelopeReplyContext(envelope, replyCtx) : envelope;
|
|
150
151
|
const receipt = await adapter.send(enriched, payload);
|
|
152
|
+
// Preserve the historical `sent` result for void-returning adapters while
|
|
153
|
+
// still accepting the newer structured SendReceipt contract.
|
|
151
154
|
if (!receipt)
|
|
152
|
-
return
|
|
155
|
+
return 'sent';
|
|
153
156
|
if (receipt.status === 'sent' && !(receipt.messageId || receipt.messages[0]?.messageId))
|
|
154
157
|
return false;
|
|
155
158
|
return receipt;
|
|
@@ -517,6 +517,7 @@ export class ResponseEngine {
|
|
|
517
517
|
/** 已主动发送开始提示时,忽略 runner 对同一次 compact 的回调。 */
|
|
518
518
|
announcedCompactStarts = new Set();
|
|
519
519
|
agentMap;
|
|
520
|
+
legacySingleRunnerMode;
|
|
520
521
|
primaryRunnerKey;
|
|
521
522
|
interruptedSessions = new Map(); // sessionId → reason ('new_message' | 'stop' | ...)
|
|
522
523
|
timeoutErrors = new Map();
|
|
@@ -552,27 +553,42 @@ export class ResponseEngine {
|
|
|
552
553
|
* session/config mismatch and must not silently route to a different backend.
|
|
553
554
|
*/
|
|
554
555
|
getAgent(channel, baseagent, selfAID) {
|
|
555
|
-
|
|
556
|
-
|
|
556
|
+
const requestedBaseagent = typeof baseagent === 'string' ? baseagent.trim() : '';
|
|
557
|
+
// Keep the explicit single-backend map shape usable by embedders and
|
|
558
|
+
// focused tests. This is an exact key lookup, not a cross-agent fallback.
|
|
559
|
+
if (requestedBaseagent && this.agentMap.has(requestedBaseagent)) {
|
|
560
|
+
return this.agentMap.get(requestedBaseagent);
|
|
561
|
+
}
|
|
562
|
+
// A caller that passed one runner explicitly has already selected the
|
|
563
|
+
// backend; this compatibility path does not exist for multi-agent maps.
|
|
564
|
+
if (this.legacySingleRunnerMode && this.agentMap.size === 1
|
|
565
|
+
&& this.agentMap.values().next().value?.name === requestedBaseagent) {
|
|
566
|
+
return this.agentMap.values().next().value;
|
|
567
|
+
}
|
|
568
|
+
if (selfAID && requestedBaseagent) {
|
|
569
|
+
const key = `${selfAID}::${requestedBaseagent}`;
|
|
557
570
|
if (this.agentMap.has(key))
|
|
558
571
|
return this.agentMap.get(key);
|
|
559
572
|
}
|
|
560
|
-
if (channel &&
|
|
573
|
+
if (channel && requestedBaseagent) {
|
|
561
574
|
const owner = this.agentRegistry?.resolveByChannel(channel);
|
|
562
575
|
const evolName = owner?.name || '<unknown>';
|
|
563
|
-
const key = `${evolName}::${
|
|
576
|
+
const key = `${evolName}::${requestedBaseagent}`;
|
|
564
577
|
if (this.agentMap.has(key))
|
|
565
578
|
return this.agentMap.get(key);
|
|
566
|
-
const singleRunnerKey = `<unknown>::${baseagent}`;
|
|
567
|
-
if (this.agentMap.has(singleRunnerKey))
|
|
568
|
-
return this.agentMap.get(singleRunnerKey);
|
|
569
579
|
if (owner) {
|
|
570
|
-
throw new BaseagentRunnerUnavailableError(evolName,
|
|
580
|
+
throw new BaseagentRunnerUnavailableError(evolName, requestedBaseagent, this.getAvailableBaseagentsForOwner(evolName));
|
|
571
581
|
}
|
|
582
|
+
// Control/test channels may have no registry owner. Resolve only when
|
|
583
|
+
// exactly one loaded runner advertises this baseagent; never choose the
|
|
584
|
+
// primary runner or the first map entry as a backend substitute.
|
|
585
|
+
const matches = [...this.agentMap.entries()]
|
|
586
|
+
.filter(([runnerKey]) => runnerKey.endsWith(`::${requestedBaseagent}`));
|
|
587
|
+
if (matches.length === 1)
|
|
588
|
+
return matches[0][1];
|
|
589
|
+
throw new BaseagentRunnerUnavailableError('<unknown>', requestedBaseagent, [...new Set(matches.map(([runnerKey]) => runnerKey.slice(runnerKey.lastIndexOf('::') + 2)))]);
|
|
572
590
|
}
|
|
573
|
-
|
|
574
|
-
return this.agentMap.get(this.primaryRunnerKey);
|
|
575
|
-
return this.agentMap.values().next().value;
|
|
591
|
+
throw new BaseagentRunnerUnavailableError('<unknown>', requestedBaseagent || '<missing>', []);
|
|
576
592
|
}
|
|
577
593
|
getTextInferenceProvider(channel, baseagent, selfAID) {
|
|
578
594
|
if (!baseagent)
|
|
@@ -648,11 +664,13 @@ export class ResponseEngine {
|
|
|
648
664
|
this.turnCoordinator = new SessionTurnCoordinator(sessionManager);
|
|
649
665
|
if (agentRunnerOrMap instanceof Map) {
|
|
650
666
|
this.agentMap = agentRunnerOrMap;
|
|
667
|
+
this.legacySingleRunnerMode = false;
|
|
651
668
|
this.primaryRunnerKey = primaryRunnerKey || '<unknown>::claude';
|
|
652
669
|
}
|
|
653
670
|
else {
|
|
654
671
|
// 测试 / 单 runner 路径:占位 agent name 用 '<unknown>'
|
|
655
672
|
this.agentMap = new Map([[`<unknown>::${agentRunnerOrMap.name}`, agentRunnerOrMap]]);
|
|
673
|
+
this.legacySingleRunnerMode = true;
|
|
656
674
|
this.primaryRunnerKey = `<unknown>::${agentRunnerOrMap.name}`;
|
|
657
675
|
}
|
|
658
676
|
// 监听中断事件,标记被中断的 session
|
|
@@ -907,14 +925,10 @@ export class ResponseEngine {
|
|
|
907
925
|
if (owning)
|
|
908
926
|
owning.lastActivity = Date.now();
|
|
909
927
|
}
|
|
910
|
-
inferPrimaryBaseagent() {
|
|
911
|
-
const idx = this.primaryRunnerKey.lastIndexOf('::');
|
|
912
|
-
return idx >= 0 ? this.primaryRunnerKey.slice(idx + 2) : this.primaryRunnerKey || undefined;
|
|
913
|
-
}
|
|
914
928
|
ensureSessionBaseagent(session, fallback) {
|
|
915
|
-
|
|
916
|
-
if (!session.baseagent) {
|
|
917
|
-
session.
|
|
929
|
+
void fallback;
|
|
930
|
+
if (typeof session.baseagent !== 'string' || !session.baseagent.trim()) {
|
|
931
|
+
throw new Error(`[ResponseEngine] session ${session.id} has no baseagent binding; refusing implicit fallback`);
|
|
918
932
|
}
|
|
919
933
|
}
|
|
920
934
|
inferDirectSessionIdentity(message, owningAgent) {
|
|
@@ -1647,6 +1661,19 @@ export class ResponseEngine {
|
|
|
1647
1661
|
totalToolCalls: result.state.totalToolCalls,
|
|
1648
1662
|
lastToolName: result.state.lastToolName,
|
|
1649
1663
|
});
|
|
1664
|
+
const idleNotice = timeoutControl.idleNotice;
|
|
1665
|
+
if (idleNotice) {
|
|
1666
|
+
void Promise.resolve(idleNotice({
|
|
1667
|
+
action: result.action,
|
|
1668
|
+
idleSec: result.idleSec,
|
|
1669
|
+
message: result.message,
|
|
1670
|
+
totalEvents: result.state.totalEvents,
|
|
1671
|
+
totalToolCalls: result.state.totalToolCalls,
|
|
1672
|
+
lastToolName: result.state.lastToolName,
|
|
1673
|
+
})).catch(error => {
|
|
1674
|
+
logger.debug(`[ResponseEngine] Idle notice send failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
1675
|
+
});
|
|
1676
|
+
}
|
|
1650
1677
|
}
|
|
1651
1678
|
result = monitor.check();
|
|
1652
1679
|
}
|
|
@@ -2401,8 +2428,10 @@ export class ResponseEngine {
|
|
|
2401
2428
|
opts.title = '\u2705 \u6700\u7ec8\u56de\u590d:';
|
|
2402
2429
|
}
|
|
2403
2430
|
opts.metadata = withTaskMetadata(opts.metadata);
|
|
2404
|
-
|
|
2431
|
+
// status.notice is a diagnostic observation, not execution activity.
|
|
2432
|
+
if (payload.kind.startsWith('status.') && payload.kind !== 'status.notice') {
|
|
2405
2433
|
this.touchAgentActivity(channelKey);
|
|
2434
|
+
}
|
|
2406
2435
|
const enrichedEnvelope = withEnvelopeReplyContext(envelope, opts);
|
|
2407
2436
|
snapshot.pushOutbound(session.id, taskId, { kind: payload.kind, decision: 'sent' });
|
|
2408
2437
|
return await adapter.send(enrichedEnvelope, payload);
|
|
@@ -2413,6 +2442,19 @@ export class ResponseEngine {
|
|
|
2413
2442
|
renderer,
|
|
2414
2443
|
suppressActivities: shouldSuppress(),
|
|
2415
2444
|
});
|
|
2445
|
+
// Idle notify/warn are operational diagnostic notices. Keep them on the
|
|
2446
|
+
// current task's renderer so envelope, stale-turn, background, and
|
|
2447
|
+
// channel-specific suppression rules remain identical to other sends.
|
|
2448
|
+
if (timeoutControl) {
|
|
2449
|
+
timeoutControl.idleNotice = async ({ action, idleSec, message: idleMessage, totalEvents, totalToolCalls, lastToolName }) => {
|
|
2450
|
+
await renderer.sendStatusNotice(idleMessage, action === 'warn' ? 'warn' : 'info', `idle-${action}`, {
|
|
2451
|
+
idleSec,
|
|
2452
|
+
totalEvents,
|
|
2453
|
+
totalToolCalls,
|
|
2454
|
+
lastToolName,
|
|
2455
|
+
});
|
|
2456
|
+
};
|
|
2457
|
+
}
|
|
2416
2458
|
renderer.addLifecycle('started');
|
|
2417
2459
|
if (isProactive) {
|
|
2418
2460
|
logger.info(`[ResponseEngine] proactive mode: outputs via thought.put task=${taskId}`);
|
|
@@ -2956,6 +2998,12 @@ export class ResponseEngine {
|
|
|
2956
2998
|
bootstrapAgentMdPath: agentMdPath(selfAid),
|
|
2957
2999
|
};
|
|
2958
3000
|
}
|
|
3001
|
+
if (selfAid && peerRole === 'owner' && effectivePermissionMode !== 'readonly') {
|
|
3002
|
+
modelOverride = {
|
|
3003
|
+
...(modelOverride || {}),
|
|
3004
|
+
personalMdPath: path.join(resolveRoot(), 'agents', selfAid, 'personal', 'personal.md'),
|
|
3005
|
+
};
|
|
3006
|
+
}
|
|
2959
3007
|
if (normalizedBaseagent.canonical === 'claude') {
|
|
2960
3008
|
modelOverride = {
|
|
2961
3009
|
...(modelOverride || {}),
|
|
@@ -3094,6 +3142,7 @@ export class ResponseEngine {
|
|
|
3094
3142
|
sessionId: session.id,
|
|
3095
3143
|
sessionName: session.name || undefined,
|
|
3096
3144
|
sessionCreatedAt: session.createdAt ? new Date(session.createdAt).toISOString() : undefined,
|
|
3145
|
+
managedTempDir: sessionRuntimeDir,
|
|
3097
3146
|
// 时区(把 ISO 时间戳转本地时间用)+ OS 环境
|
|
3098
3147
|
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone || undefined,
|
|
3099
3148
|
tzOffset: currentTzOffset(),
|
|
@@ -3142,7 +3191,10 @@ export class ResponseEngine {
|
|
|
3142
3191
|
try {
|
|
3143
3192
|
const estTokens = (s) => s ? Math.ceil(s.length / 4) : 0;
|
|
3144
3193
|
const cbModel = effectiveModel || agentModel || 'unknown';
|
|
3145
|
-
|
|
3194
|
+
// 从统一模型参数表获取模型的真实 context_window
|
|
3195
|
+
const { resolveModelSpec } = await import('../../stats/billing.js');
|
|
3196
|
+
const modelSpec = resolveModelSpec(resolveRoot(), cbModel);
|
|
3197
|
+
const cbMaxTokens = modelSpec.context_window;
|
|
3146
3198
|
const systemPromptTokens = estTokens(options?.systemPromptAppend);
|
|
3147
3199
|
const kitTokens = estTokens(kitContext);
|
|
3148
3200
|
const totalEst = estTokens(effectiveSystemPrompt);
|
|
@@ -3315,6 +3367,8 @@ export class ResponseEngine {
|
|
|
3315
3367
|
selfAid,
|
|
3316
3368
|
peerKey,
|
|
3317
3369
|
issuedRole: peerRole,
|
|
3370
|
+
permissionMode: effectivePermissionMode,
|
|
3371
|
+
...(sessionRuntimeDir ? { sessionRuntimeDir } : {}),
|
|
3318
3372
|
...(fullAccessAuthorization ? { executionIdentity: fullAccessAuthorization } : {}),
|
|
3319
3373
|
});
|
|
3320
3374
|
runtimeEnv[AGENT_DELEGATION_TOKEN_ENV] = delegationToken;
|
|
@@ -4513,12 +4567,12 @@ export class ResponseEngine {
|
|
|
4513
4567
|
return undefined;
|
|
4514
4568
|
const shouldClose = !writerDb;
|
|
4515
4569
|
try {
|
|
4516
|
-
const row = db.prepare(`SELECT model, input_tokens, cache_creation_tokens, cache_read_tokens,
|
|
4517
|
-
context_tokens, max_tokens, auto_compact_tokens
|
|
4518
|
-
FROM model_calls
|
|
4519
|
-
WHERE session_id = ?
|
|
4520
|
-
AND agent_session_id = ?
|
|
4521
|
-
ORDER BY ts DESC, call_index DESC
|
|
4570
|
+
const row = db.prepare(`SELECT model, input_tokens, cache_creation_tokens, cache_read_tokens,
|
|
4571
|
+
context_tokens, max_tokens, auto_compact_tokens
|
|
4572
|
+
FROM model_calls
|
|
4573
|
+
WHERE session_id = ?
|
|
4574
|
+
AND agent_session_id = ?
|
|
4575
|
+
ORDER BY ts DESC, call_index DESC
|
|
4522
4576
|
LIMIT 1`).get(sessionId, agentSessionId);
|
|
4523
4577
|
if (!row)
|
|
4524
4578
|
return undefined;
|
|
@@ -4572,7 +4626,7 @@ export class ResponseEngine {
|
|
|
4572
4626
|
: undefined;
|
|
4573
4627
|
const owningAgent = this.agentRegistry?.resolveByChannel(message.channel);
|
|
4574
4628
|
const projectPath = owningAgent?.projectPath || process.cwd();
|
|
4575
|
-
const resolvedBaseagent = message.baseagent || owningAgent?.baseagent
|
|
4629
|
+
const resolvedBaseagent = message.baseagent || owningAgent?.baseagent;
|
|
4576
4630
|
// 优先复用 MessageBridge 入队前已解析的身份,避免二次独立解析产生角色漂移
|
|
4577
4631
|
// (曾观测到瞬时竞态下把 owner 误判为 none,导致合法用户被静默拒绝)。
|
|
4578
4632
|
// 仅当消息不经 MessageBridge.register()(如 trigger 直接投递)时才回退重新解析。
|
|
@@ -4762,6 +4816,10 @@ export class ResponseEngine {
|
|
|
4762
4816
|
// 每收到事件重置空闲超时
|
|
4763
4817
|
const toolName = event.type === 'tool_use' ? event.name : undefined;
|
|
4764
4818
|
resetTimer(event.type, toolName);
|
|
4819
|
+
// Provider reasoning/thinking is an internal liveness signal only.
|
|
4820
|
+
// It must never be projected as progress, activity, text, or transcript.
|
|
4821
|
+
if (event.type === 'heartbeat')
|
|
4822
|
+
continue;
|
|
4765
4823
|
if (event.type === 'input_accepted') {
|
|
4766
4824
|
inputAccepted = !turnLease || event.inputId === turnLease.inputId;
|
|
4767
4825
|
logger.debug(`[ResponseEngine] Input accepted: session=${session.id} input=${event.inputId}`);
|
|
@@ -43,7 +43,9 @@ export function parseModelList(json, _url) {
|
|
|
43
43
|
const rawId = typeof item === 'string' ? item : item?.id ?? item?.slug ?? item?.name ?? item?.model;
|
|
44
44
|
if (typeof rawId !== 'string' || !rawId.trim())
|
|
45
45
|
continue;
|
|
46
|
-
|
|
46
|
+
// 规范化模型 ID:去掉 Claude Code SDK 的上下文窗口后缀 [1m]/[200k]
|
|
47
|
+
// 这些后缀只在传给 claude baseagent 时由 applyContextWindow 添加
|
|
48
|
+
const id = rawId.trim().replace(/\[(?:1m|200k)\]$/i, '');
|
|
47
49
|
if (out.has(id))
|
|
48
50
|
continue;
|
|
49
51
|
const rawLevels = item?.reasoningLevels ?? item?.supportedReasoningEfforts ?? item?.supported_reasoning_levels;
|
|
@@ -106,6 +106,16 @@ export function resolveCatalogContext(self, ba) {
|
|
|
106
106
|
}
|
|
107
107
|
return context;
|
|
108
108
|
}
|
|
109
|
+
const HOST_BASEAGENTS = ['claude', 'codex', 'ecagent', 'gemini'];
|
|
110
|
+
/** Query the catalog for a host-level default connection, without Agent scope. */
|
|
111
|
+
export async function getBaseagentCatalog(baseagent, options = {}) {
|
|
112
|
+
if (!HOST_BASEAGENTS.includes(baseagent)) {
|
|
113
|
+
throw Object.assign(new Error(`Invalid baseagent: ${baseagent}. Valid: ${HOST_BASEAGENTS.join(', ')}`), { code: 'INVALID_ARGUMENT' });
|
|
114
|
+
}
|
|
115
|
+
const normalized = baseagent;
|
|
116
|
+
const snapshot = await getCatalog(undefined, normalized, options.refresh === true);
|
|
117
|
+
return { ...snapshot, baseagent: normalized };
|
|
118
|
+
}
|
|
109
119
|
/** Used by the IPC handler and the owner process. Never calls IPC recursively. */
|
|
110
120
|
export async function getLocalCatalog(self, ba, refresh = false) {
|
|
111
121
|
return service.get(resolveCatalogContext(self, ba), refresh);
|
|
@@ -7,12 +7,15 @@ export function isModelAllowedByPatterns(model, allowedModels) {
|
|
|
7
7
|
: model === pattern);
|
|
8
8
|
}
|
|
9
9
|
function normalizeBaseagent(baseagent) {
|
|
10
|
-
|
|
10
|
+
const normalized = typeof baseagent === 'string' ? baseagent.trim() : '';
|
|
11
|
+
return normalized || undefined;
|
|
11
12
|
}
|
|
12
13
|
export function getRoleModelPermission(role, baseagent, selfAid) {
|
|
13
14
|
const ba = normalizeBaseagent(baseagent);
|
|
14
15
|
if (!role)
|
|
15
16
|
return { allowOverride: false, constrained: true };
|
|
17
|
+
if (!ba)
|
|
18
|
+
return { allowOverride: false, constrained: true, allowedModels: [] };
|
|
16
19
|
const selected = getFieldPermission(role, `baseagents.${ba}.model`, selfAid);
|
|
17
20
|
if (!selected || !Array.isArray(selected.allowedModels)) {
|
|
18
21
|
return { allowOverride: true, constrained: false };
|
|
@@ -8,7 +8,7 @@ import { createRootCausation, deriveCausation, normalizeCausation } from '../cau
|
|
|
8
8
|
import { recordCausationSpan } from '../causation/audit.js';
|
|
9
9
|
import { checkDangerousCommand } from './tool-policy.js';
|
|
10
10
|
import { resolveProtectedCandidate } from './protected-paths.js';
|
|
11
|
-
import { auditPermissionDecision } from '../auth/authorization-audit.js';
|
|
11
|
+
import { auditPermissionDecision, auditPermissionLifecycle } from '../auth/authorization-audit.js';
|
|
12
12
|
export async function requestDangerousCommandPermission(gateway, sessionId, toolName, input, sendPrompt, context, grantScope = 'default', mode = 'request') {
|
|
13
13
|
const dangerCheck = checkDangerousCommand(toolName, input);
|
|
14
14
|
if (!dangerCheck.isDangerous) {
|
|
@@ -448,22 +448,40 @@ export class PermissionGateway {
|
|
|
448
448
|
if (sessionGrant)
|
|
449
449
|
this.addTemporaryGrant(pending, decisionCausation);
|
|
450
450
|
pending.resolve(decision);
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
451
|
+
auditPermissionLifecycle({
|
|
452
|
+
phase: 'response',
|
|
453
|
+
requestId,
|
|
454
|
+
sessionId,
|
|
455
|
+
toolName: pending.toolName,
|
|
456
|
+
decision: approved ? 'allow' : 'deny',
|
|
457
|
+
decisionSource: 'approval',
|
|
458
|
+
policyCode: approved ? undefined : 'user_approval_denied',
|
|
459
|
+
reason: approved ? 'owner approval accepted' : 'owner approval denied',
|
|
460
|
+
permissionMode: pending.permissionMode,
|
|
461
|
+
agentAid: pending.selfAid,
|
|
462
|
+
agentName: pending.agentName,
|
|
463
|
+
role: pending.role,
|
|
464
|
+
taskId: pending.taskId,
|
|
465
|
+
summary: pending.auditSummary,
|
|
466
|
+
response: action,
|
|
467
|
+
});
|
|
468
|
+
auditPermissionLifecycle({
|
|
469
|
+
phase: 'final',
|
|
470
|
+
requestId,
|
|
471
|
+
sessionId,
|
|
472
|
+
toolName: pending.toolName,
|
|
473
|
+
decision: approved ? 'allow' : 'deny',
|
|
474
|
+
decisionSource: 'approval',
|
|
475
|
+
policyCode: approved ? undefined : 'user_approval_denied',
|
|
476
|
+
reason: approved ? 'owner approval accepted' : 'owner approval denied',
|
|
477
|
+
permissionMode: pending.permissionMode,
|
|
478
|
+
agentAid: pending.selfAid,
|
|
479
|
+
agentName: pending.agentName,
|
|
480
|
+
role: pending.role,
|
|
481
|
+
taskId: pending.taskId,
|
|
482
|
+
summary: pending.auditSummary,
|
|
483
|
+
response: action,
|
|
484
|
+
});
|
|
467
485
|
void this.notifyPermissionState(pending, approved
|
|
468
486
|
? { state: 'approved', requestId, toolName: pending.toolName }
|
|
469
487
|
: {
|
|
@@ -502,6 +520,23 @@ export class PermissionGateway {
|
|
|
502
520
|
pending.resolve('deny');
|
|
503
521
|
const decisionSource = 'infrastructure';
|
|
504
522
|
const policyCode = cancelled ? 'approval_cancelled' : `approval_${reason}`;
|
|
523
|
+
auditPermissionLifecycle({
|
|
524
|
+
phase: 'response',
|
|
525
|
+
requestId,
|
|
526
|
+
sessionId,
|
|
527
|
+
toolName: pending.toolName,
|
|
528
|
+
decision: 'deny',
|
|
529
|
+
decisionSource,
|
|
530
|
+
policyCode,
|
|
531
|
+
reason,
|
|
532
|
+
permissionMode: pending.permissionMode,
|
|
533
|
+
agentAid: pending.selfAid,
|
|
534
|
+
agentName: pending.agentName,
|
|
535
|
+
role: pending.role,
|
|
536
|
+
taskId: pending.taskId,
|
|
537
|
+
summary: pending.auditSummary,
|
|
538
|
+
response: reason,
|
|
539
|
+
});
|
|
505
540
|
auditPermissionDecision({
|
|
506
541
|
requestId,
|
|
507
542
|
sessionId,
|
|
@@ -565,7 +600,25 @@ export class PermissionGateway {
|
|
|
565
600
|
const auditSummary = summarizeToolInputForAudit(challenge.toolName, challenge.toolInput).slice(0, 512);
|
|
566
601
|
if (!approval || !interactionRouter) {
|
|
567
602
|
await sendPrompt('当前会话权限不足,且没有可用的 owner 审批通道。');
|
|
603
|
+
auditPermissionLifecycle({
|
|
604
|
+
phase: 'response',
|
|
605
|
+
requestId: challenge.id,
|
|
606
|
+
sessionId,
|
|
607
|
+
toolName: challenge.toolName,
|
|
608
|
+
decision: 'deny',
|
|
609
|
+
decisionSource: 'infrastructure',
|
|
610
|
+
policyCode: 'approval_route_unavailable',
|
|
611
|
+
reason: 'owner approval routing context is unavailable',
|
|
612
|
+
permissionMode: context.permissionMode,
|
|
613
|
+
agentAid: context.selfAid,
|
|
614
|
+
agentName: context.agentName,
|
|
615
|
+
role: context.role,
|
|
616
|
+
taskId: context.taskId,
|
|
617
|
+
summary: auditSummary,
|
|
618
|
+
response: 'unavailable',
|
|
619
|
+
});
|
|
568
620
|
auditPermissionDecision({
|
|
621
|
+
requestId: challenge.id,
|
|
569
622
|
sessionId,
|
|
570
623
|
toolName: challenge.toolName,
|
|
571
624
|
decisionSource: 'infrastructure',
|
|
@@ -783,6 +836,23 @@ export class PermissionGateway {
|
|
|
783
836
|
this.syncManagementRevalidationTimer();
|
|
784
837
|
pending.resolve('deny');
|
|
785
838
|
const decisionSource = reason === 'denied' ? 'approval' : 'infrastructure';
|
|
839
|
+
auditPermissionLifecycle({
|
|
840
|
+
phase: 'response',
|
|
841
|
+
requestId,
|
|
842
|
+
sessionId,
|
|
843
|
+
toolName: pending.toolName,
|
|
844
|
+
decision: 'deny',
|
|
845
|
+
decisionSource,
|
|
846
|
+
policyCode: `approval_${reason}`,
|
|
847
|
+
reason,
|
|
848
|
+
permissionMode: pending.permissionMode,
|
|
849
|
+
agentAid: pending.selfAid,
|
|
850
|
+
agentName: pending.agentName,
|
|
851
|
+
role: pending.role,
|
|
852
|
+
taskId: pending.taskId,
|
|
853
|
+
summary: pending.auditSummary,
|
|
854
|
+
response: reason,
|
|
855
|
+
});
|
|
786
856
|
auditPermissionDecision({
|
|
787
857
|
requestId,
|
|
788
858
|
sessionId,
|
|
@@ -915,6 +985,20 @@ export class PermissionGateway {
|
|
|
915
985
|
refs: { permissionRequestId: requestId, taskId: context.taskId, sessionId },
|
|
916
986
|
});
|
|
917
987
|
this.eventBus?.publish({ type: 'permission:requested', sessionId, requestId, toolName, input: displaySummary, causation: requestCausation });
|
|
988
|
+
auditPermissionLifecycle({
|
|
989
|
+
phase: 'request',
|
|
990
|
+
requestId,
|
|
991
|
+
sessionId,
|
|
992
|
+
toolName,
|
|
993
|
+
decision: 'pending',
|
|
994
|
+
decisionSource: 'approval',
|
|
995
|
+
permissionMode: context?.permissionMode,
|
|
996
|
+
agentAid: context?.selfAid,
|
|
997
|
+
agentName: context?.agentName,
|
|
998
|
+
role: context?.role,
|
|
999
|
+
taskId: context?.taskId,
|
|
1000
|
+
summary: auditSummary,
|
|
1001
|
+
});
|
|
918
1002
|
const route = planApprovalRoute(challenge, context);
|
|
919
1003
|
logger.info(`[PermissionGateway] approval_route request=${requestId} policy=${challenge.approverPolicy}`
|
|
920
1004
|
+ ` route=${route.kind}`
|
|
@@ -955,6 +1039,23 @@ export class PermissionGateway {
|
|
|
955
1039
|
taskId: context.taskId,
|
|
956
1040
|
summary: summarizeToolInputForAudit(toolName, toolInput).slice(0, 512),
|
|
957
1041
|
});
|
|
1042
|
+
auditPermissionLifecycle({
|
|
1043
|
+
phase: 'response',
|
|
1044
|
+
requestId,
|
|
1045
|
+
sessionId,
|
|
1046
|
+
toolName,
|
|
1047
|
+
decision: 'deny',
|
|
1048
|
+
decisionSource: 'infrastructure',
|
|
1049
|
+
policyCode: 'approval_route_unavailable',
|
|
1050
|
+
reason: route.reason,
|
|
1051
|
+
permissionMode: context.permissionMode,
|
|
1052
|
+
agentAid: context.selfAid,
|
|
1053
|
+
agentName: context.agentName,
|
|
1054
|
+
role: context.role,
|
|
1055
|
+
taskId: context.taskId,
|
|
1056
|
+
summary: summarizeToolInputForAudit(toolName, toolInput).slice(0, 512),
|
|
1057
|
+
response: 'unavailable',
|
|
1058
|
+
});
|
|
958
1059
|
return 'deny';
|
|
959
1060
|
}
|
|
960
1061
|
if (route.kind === 'handoff') {
|
|
@@ -1125,6 +1226,40 @@ export class PermissionGateway {
|
|
|
1125
1226
|
pending.resolve(normalizedDecision === 'deny' ? 'deny' : 'allow');
|
|
1126
1227
|
this.pending.delete(requestId);
|
|
1127
1228
|
this.syncManagementRevalidationTimer();
|
|
1229
|
+
auditPermissionLifecycle({
|
|
1230
|
+
phase: 'response',
|
|
1231
|
+
requestId,
|
|
1232
|
+
sessionId,
|
|
1233
|
+
toolName: pending.toolName,
|
|
1234
|
+
decision: normalizedDecision === 'deny' ? 'deny' : 'allow',
|
|
1235
|
+
decisionSource: 'approval',
|
|
1236
|
+
policyCode: normalizedDecision === 'deny' ? 'user_approval_denied' : undefined,
|
|
1237
|
+
reason: normalizedDecision === 'deny' ? 'user approval denied' : 'user approval accepted',
|
|
1238
|
+
permissionMode: pending.permissionMode,
|
|
1239
|
+
agentAid: pending.selfAid,
|
|
1240
|
+
agentName: pending.agentName,
|
|
1241
|
+
role: pending.role,
|
|
1242
|
+
taskId: pending.taskId,
|
|
1243
|
+
summary: pending.auditSummary,
|
|
1244
|
+
response: normalizedDecision,
|
|
1245
|
+
});
|
|
1246
|
+
auditPermissionLifecycle({
|
|
1247
|
+
phase: 'final',
|
|
1248
|
+
requestId,
|
|
1249
|
+
sessionId,
|
|
1250
|
+
toolName: pending.toolName,
|
|
1251
|
+
decision: normalizedDecision === 'deny' ? 'deny' : 'allow',
|
|
1252
|
+
decisionSource: 'approval',
|
|
1253
|
+
policyCode: normalizedDecision === 'deny' ? 'user_approval_denied' : undefined,
|
|
1254
|
+
reason: normalizedDecision === 'deny' ? 'user approval denied' : 'user approval accepted',
|
|
1255
|
+
permissionMode: pending.permissionMode,
|
|
1256
|
+
agentAid: pending.selfAid,
|
|
1257
|
+
agentName: pending.agentName,
|
|
1258
|
+
role: pending.role,
|
|
1259
|
+
taskId: pending.taskId,
|
|
1260
|
+
summary: pending.auditSummary,
|
|
1261
|
+
response: normalizedDecision,
|
|
1262
|
+
});
|
|
1128
1263
|
const decisionCausation = deriveCausation(pending.causation);
|
|
1129
1264
|
if (normalizedDecision === 'always') {
|
|
1130
1265
|
this.addTemporaryGrant(pending, decisionCausation);
|
|
@@ -1136,22 +1271,6 @@ export class PermissionGateway {
|
|
|
1136
1271
|
});
|
|
1137
1272
|
const decisionSource = 'approval';
|
|
1138
1273
|
const policyCode = normalizedDecision === 'deny' ? 'user_approval_denied' : undefined;
|
|
1139
|
-
if (normalizedDecision === 'deny') {
|
|
1140
|
-
auditPermissionDecision({
|
|
1141
|
-
requestId,
|
|
1142
|
-
sessionId,
|
|
1143
|
-
toolName: pending.toolName,
|
|
1144
|
-
decisionSource,
|
|
1145
|
-
policyCode: 'user_approval_denied',
|
|
1146
|
-
reason: 'user approval denied',
|
|
1147
|
-
permissionMode: pending.permissionMode,
|
|
1148
|
-
agentAid: pending.selfAid,
|
|
1149
|
-
agentName: pending.agentName,
|
|
1150
|
-
role: pending.role,
|
|
1151
|
-
taskId: pending.taskId,
|
|
1152
|
-
summary: pending.auditSummary,
|
|
1153
|
-
});
|
|
1154
|
-
}
|
|
1155
1274
|
this.eventBus?.publish({ type: 'permission:resolved', sessionId, requestId, toolName: pending.toolName, approved: normalizedDecision !== 'deny', ...(policyCode ? { decisionSource, policyCode } : { decisionSource }), causation: decisionCausation });
|
|
1156
1275
|
return true;
|
|
1157
1276
|
}
|
|
@@ -1215,6 +1334,23 @@ export class PermissionGateway {
|
|
|
1215
1334
|
this.clearPendingResources(pending);
|
|
1216
1335
|
pending.interactionRouter?.cancel(requestId, reason);
|
|
1217
1336
|
pending.resolve('deny');
|
|
1337
|
+
auditPermissionLifecycle({
|
|
1338
|
+
phase: 'response',
|
|
1339
|
+
requestId,
|
|
1340
|
+
sessionId,
|
|
1341
|
+
toolName: pending.toolName,
|
|
1342
|
+
decision: 'deny',
|
|
1343
|
+
decisionSource: 'infrastructure',
|
|
1344
|
+
policyCode: `approval_${reason}`,
|
|
1345
|
+
reason,
|
|
1346
|
+
permissionMode: pending.permissionMode,
|
|
1347
|
+
agentAid: pending.selfAid,
|
|
1348
|
+
agentName: pending.agentName,
|
|
1349
|
+
role: pending.role,
|
|
1350
|
+
taskId: pending.taskId,
|
|
1351
|
+
summary: pending.auditSummary,
|
|
1352
|
+
response: reason,
|
|
1353
|
+
});
|
|
1218
1354
|
auditPermissionDecision({
|
|
1219
1355
|
requestId,
|
|
1220
1356
|
sessionId,
|