mixdog 1.3.2 → 1.3.4
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/package.json +8 -8
- package/scripts/verify-runtime-dependency-versions.mjs +158 -0
- package/src/agents/reviewer/AGENT.md +5 -7
- package/src/agents/reviewer/agent.json +1 -1
- package/src/defaults/shipped-history.json +4 -0
- package/src/defaults/skills/browser-use/SKILL.md +6 -3
- package/src/defaults/skills/local-provider/SKILL.md +33 -6
- package/src/rules/lead/LEAD.md +5 -8
- package/src/rules/shared/45-destructive.md +5 -1
- package/src/rules/shared/60-verification.md +6 -4
- package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +4 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens.mjs +38 -11
- package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +15 -3
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +17 -4
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +14 -1
- package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/custom-provider-config.mjs +14 -1
- package/src/runtime/agent/orchestrator/providers/grok-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/registry.mjs +10 -0
- package/src/runtime/agent/orchestrator/providers/wire-gateway.mjs +13 -1
- package/src/runtime/agent/orchestrator/runtime-core/goal-runtime.mjs +5 -0
- package/src/runtime/agent/orchestrator/runtime-core/goal-turns.mjs +10 -1
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +40 -5
- package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +32 -11
- package/src/runtime/agent/orchestrator/runtime-core/workflow.mjs +6 -3
- package/src/runtime/agent/orchestrator/session/agent-loop.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/agent-room.d.mts +13 -0
- package/src/runtime/agent/orchestrator/session/agent-room.mjs +68 -12
- package/src/runtime/agent/orchestrator/session/compact/continuation.mjs +15 -6
- package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +31 -8
- package/src/runtime/agent/orchestrator/session/compact/messages.mjs +44 -0
- package/src/runtime/agent/orchestrator/session/compact/runner.mjs +117 -19
- package/src/runtime/agent/orchestrator/session/compact/text-utils.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/compact/user-message-kind.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/human-gate/delegation.mjs +147 -137
- package/src/runtime/agent/orchestrator/session/human-gate/gate.mjs +37 -74
- package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +0 -2
- package/src/runtime/agent/orchestrator/session/human-gate/run-policy.mjs +2 -2
- package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +13 -7
- package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +5 -0
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/continuation.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/empty-nudge.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/output-limit.mjs +62 -13
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +22 -6
- package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +7 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +12 -20
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/call-prep.mjs +5 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +11 -5
- package/src/runtime/agent/orchestrator/session/manager/agent-listing-notice.mjs +102 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-queue.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +13 -1
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +24 -15
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +8 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-steering-drain.mjs +1 -0
- package/src/runtime/agent/orchestrator/session/manager/idle-cleanup.mjs +32 -1
- package/src/runtime/agent/orchestrator/session/manager/orchestration-mode-switch-notice.mjs +17 -1
- package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +6 -0
- package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +36 -0
- package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +28 -9
- package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +7 -5
- package/src/runtime/agent/orchestrator/session/manager/session-tool-surface.mjs +7 -3
- package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +10 -1
- package/src/runtime/agent/orchestrator/session/routine-result.mjs +7 -4
- package/src/runtime/agent/orchestrator/session/runtime-user-context.mjs +3 -1
- package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +11 -2
- package/src/runtime/agent/orchestrator/session/store/sweep/stale-sweep.mjs +5 -4
- package/src/runtime/agent/orchestrator/session/store/sweep/sub-agent-retention.mjs +140 -0
- package/src/runtime/agent/orchestrator/session/store/sweep/sweep-plan.mjs +5 -0
- package/src/runtime/agent/orchestrator/session/store/sweep/sweep-record.mjs +7 -2
- package/src/runtime/agent/orchestrator/session/store/sweep/sweep-row.mjs +13 -0
- package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +76 -0
- package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +33 -1
- package/src/runtime/agent/orchestrator/session/store-summary-visibility.d.mts +5 -0
- package/src/runtime/agent/orchestrator/session/store-summary-visibility.mjs +37 -0
- package/src/runtime/agent/orchestrator/session/store.mjs +1 -0
- package/src/runtime/agent/orchestrator/tools/builtin/advisory-lock.mjs +18 -7
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/backgrounded-result.mjs +2 -0
- package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +127 -20
- package/src/runtime/agent/orchestrator/tools/builtin/git-worktree-tool.mjs +557 -0
- package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +6 -0
- package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +8 -2
- package/src/runtime/attachments/legacy-office.mjs +110 -0
- package/src/runtime/attachments/prompt-restore.mjs +70 -0
- package/src/runtime/attachments/store.mjs +60 -3
- package/src/runtime/effort-judge/judge-client.mjs +61 -14
- package/src/runtime/effort-judge/model-install.mjs +34 -2
- package/src/runtime/memory/lib/memory-chunk-quality.mjs +14 -2
- package/src/runtime/office/portable/portable-soffice.mjs +132 -30
- package/src/runtime/shared/agent-avatar-sprites.mjs +23 -8
- package/src/runtime/shared/agent-avatar.mjs +3 -2
- package/src/runtime/shared/agent-room-host.d.mts +31 -0
- package/src/runtime/shared/agent-room-host.mjs +58 -0
- package/src/runtime/shared/bot-hops.mjs +16 -11
- package/src/runtime/shared/llm/usage-rollup.mjs +4 -383
- package/src/runtime/shared/redact-directories.mjs +18 -0
- package/src/runtime/shared/remove-directory.mjs +28 -0
- package/src/runtime/shared/session-sidebar-host.d.mts +11 -2
- package/src/runtime/shared/session-sidebar-host.mjs +16 -3
- package/src/runtime/shared/tool-execution-contract.mjs +4 -0
- package/src/runtime/shared/tool-work-units.mjs +12 -9
- package/src/runtime/shared/turn-snapshot.mjs +233 -122
- package/src/runtime/shared/user-data-guard.mjs +51 -19
- package/src/runtime/shared/worktrees/activity-gate.mjs +209 -227
- package/src/runtime/shared/worktrees/contract.mjs +11 -3
- package/src/runtime/shared/worktrees/maintenance.mjs +11 -2
- package/src/runtime/shared/worktrees/manager.mjs +419 -52
- package/src/runtime/shared/worktrees/registry.mjs +3 -1
- package/src/runtime/shared/worktrees/tool-host.mjs +39 -0
- package/src/runtime/tidy/process.mjs +41 -8
- package/src/runtime/tidy/resolve.mjs +10 -7
- package/src/session-runtime/agent-home-delivery.mjs +73 -91
- package/src/session-runtime/agent-profile-changes.mjs +16 -0
- package/src/session-runtime/agent-room-delivery.mjs +2 -63
- package/src/session-runtime/agent-task-sessions.mjs +194 -64
- package/src/session-runtime/agent-tool-routing.mjs +49 -4
- package/src/session-runtime/boot/apis.mjs +3 -0
- package/src/session-runtime/boot/facade.mjs +5 -6
- package/src/session-runtime/boot/tools.mjs +23 -1
- package/src/session-runtime/held-requests.mjs +20 -25
- package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +5 -22
- package/src/session-runtime/model-recency.mjs +1 -0
- package/src/session-runtime/provider-models/row-hydration.mjs +8 -1
- package/src/session-runtime/quick-model-rows/model-meta.mjs +2 -0
- package/src/session-runtime/quick-model-rows/provider-rows.mjs +7 -1
- package/src/session-runtime/runtime-review-api.mjs +4 -1
- package/src/session-runtime/services/agent-tool/close-flow.mjs +14 -2
- package/src/session-runtime/services/agent-tool/execute.mjs +6 -1
- package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +44 -20
- package/src/session-runtime/services/agent-tool/render.mjs +3 -1
- package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +3 -0
- package/src/session-runtime/services/agent-tool/tool-def.mjs +1 -1
- package/src/session-runtime/services/provider-admin.mjs +12 -2
- package/src/session-runtime/services/worktree-access.mjs +27 -0
- package/src/session-runtime/session-hooks.mjs +9 -17
- package/src/session-runtime/settings-builtin-tools-api.mjs +2 -0
- package/src/session-runtime/setup-tool/executor.mjs +4 -0
- package/src/session-runtime/setup-tool/settings-contract.mjs +3 -0
- package/src/session-runtime/tool-policy/agent-profile-fold.mjs +98 -14
- package/src/session-runtime/tool-policy/policy-stage.mjs +23 -5
- package/src/session-runtime/tool-policy-refresh.mjs +1 -0
- package/src/session-runtime/tool-surface.mjs +9 -5
- package/src/session-runtime/turn/session-ops.mjs +8 -0
- package/src/session-runtime/turn/turn-run.mjs +5 -1
- package/src/session-runtime/usage-stats-api.mjs +1 -1
- package/src/session-runtime/workflow-agents-api/agent-editor.mjs +10 -2
- package/src/session-runtime/workflow-agents-api/agent-route.mjs +39 -17
- package/src/session-runtime/workspace/transition-steps.mjs +1 -18
- package/src/session-runtime/workspace/transitions.mjs +279 -67
- package/src/session-runtime/workspace/worktree-tool.mjs +194 -0
- package/src/standalone/daemon-lag-profiler.mjs +3 -1
- package/src/standalone/daemon-session-control.mjs +140 -23
- package/src/standalone/daemon-telemetry.mjs +9 -0
- package/src/standalone/daemon.mjs +5 -0
- package/src/standalone/local-session-runtime.mjs +11 -2
- package/src/standalone/session-protocol.mjs +1 -0
- package/src/standalone/session-runtime-inline-host/boot-loaders.mjs +2 -0
- package/src/standalone/session-service/agent-route-follow.mjs +69 -0
- package/src/standalone/session-service/session-calls/session-turns.mjs +33 -4
- package/src/standalone/session-service.mjs +10 -0
- package/src/standalone/session-tool-output.mjs +1 -0
- package/src/standalone/staged-import.mjs +47 -0
- package/src/tui/App.jsx +2 -0
- package/src/tui/app/message-selector.mjs +15 -2
- package/src/tui/app/model-options.mjs +16 -2
- package/src/tui/app/model-picker.mjs +2 -1
- package/src/tui/app/route-pickers.mjs +3 -1
- package/src/tui/dist/index.mjs +403 -210
- package/src/tui/paste-attachments.mjs +0 -1
- package/src/tui/paste-text-policy.mjs +4 -5
- package/src/tui/session/agent-job-feed/execution-delivery.mjs +4 -1
- package/src/tui/session/notice-surface.mjs +3 -0
- package/src/tui/session/session-api/intake/abort.mjs +33 -17
- package/src/tui/session/session-api/intake/rewind.mjs +39 -4
- package/src/tui/session/session-api/routes-agent-definitions.mjs +1 -0
- package/src/tui/session/tool-approval.mjs +11 -48
- package/src/vendor/statusline/src/gateway/claude-current.mjs +0 -58
- package/src/vendor/statusline/src/gateway/route-meta.mjs +1 -361
- package/src/vendor/statusline/src/gateway/session-routes.mjs +0 -55
- package/src/session-runtime/room-member-gate.mjs +0 -61
- package/src/vendor/statusline/scripts/lib/gateway-settings.mjs +0 -285
|
@@ -1,29 +1,35 @@
|
|
|
1
1
|
// session/human-gate/delegation.mjs
|
|
2
2
|
// Who a delegated session works for, recorded when it is created and re-bound
|
|
3
3
|
// only when another session sends it work (rebindDelegation): a sub-agent (any
|
|
4
|
-
// depth)
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
4
|
+
// depth) carries `delegation` on its session record —
|
|
5
|
+
// { rootSessionId, via, path }
|
|
6
|
+
// `rootSessionId` is the top-level conversation the work started in; `via`
|
|
7
|
+
// says what it is: 'coding' (a coding Lead's session or a task session a bot
|
|
8
|
+
// created) or 'bot' (a bot's own home chat or room member session); either way
|
|
9
|
+
// the agents under it mirror their ordinary approval cards into that root, but
|
|
10
|
+
// a 'bot' root's sub-agents are no bot: they ask no bot approval and use no
|
|
11
|
+
// bot grant. `path` is the agent steps from the root down
|
|
12
|
+
// ({ kind: 'agent', agent }).
|
|
13
|
+
// A task session a bot created is an ordinary coding Lead session: top-level,
|
|
14
|
+
// never delegated from the bot, and its sub-agents are rooted at it.
|
|
13
15
|
// It is copied from the parent's record (or bound from the parent itself when
|
|
14
16
|
// the parent is top-level) by the host at creation — never from tool input —
|
|
15
|
-
// so no parent walk happens at gate time.
|
|
16
|
-
//
|
|
17
|
-
//
|
|
18
|
-
//
|
|
19
|
-
//
|
|
20
|
-
//
|
|
21
|
-
//
|
|
22
|
-
//
|
|
23
|
-
//
|
|
24
|
-
//
|
|
25
|
-
//
|
|
26
|
-
|
|
17
|
+
// so no parent walk happens at gate time. When a session sends an existing
|
|
18
|
+
// worker a new request, the record is re-bound to that sender's root. A
|
|
19
|
+
// record from before this field existed, or one stored in an older shape (a
|
|
20
|
+
// task step in its path, a home/room/run/unknown `via`), is derived again from
|
|
21
|
+
// its parent by the same rules (backfillOf) and kept on the in-memory record,
|
|
22
|
+
// which its next save persists. A session that has a parent link but no valid
|
|
23
|
+
// or derivable root has no delegation (it is no bot's own session either).
|
|
24
|
+
// Work a schedule/webhook run started (a sub-agent, a task session) carries the
|
|
25
|
+
// `run` it was started under on its record, stamped at creation from its
|
|
26
|
+
// creator (never from creation options or tool input) and re-stamped, whether
|
|
27
|
+
// or not a root resolves, when another session sends it work (`run: null` =
|
|
28
|
+
// attended). A record from before the stamp keeps the run it recorded (an old
|
|
29
|
+
// `via: 'run'` delegation, an `agent:<bot>@run` task source, or its parent's
|
|
30
|
+
// run when it recorded no delegation): that is stamped before its delegation is
|
|
31
|
+
// derived again, which would drop it.
|
|
32
|
+
import { agentIdOfHomeSession } from '../agent-home.mjs';
|
|
27
33
|
import { roomMemberOfSession } from '../agent-room.mjs';
|
|
28
34
|
import { loadSession } from '../store/load-session.mjs';
|
|
29
35
|
import { _liveSessions } from '../store/live-state.mjs';
|
|
@@ -31,8 +37,7 @@ import { saveSessionAsync } from '../store/save-worker.mjs';
|
|
|
31
37
|
import { isTurnInFlight, runtimeState } from '../manager/runtime-state.mjs';
|
|
32
38
|
import { unattendedApprovalPort } from './unattended-port.mjs';
|
|
33
39
|
|
|
34
|
-
const VIA = new Set(['
|
|
35
|
-
const AGENT_ID = /^[A-Za-z0-9_-]+$/;
|
|
40
|
+
const VIA = new Set(['coding', 'bot']);
|
|
36
41
|
const MAX_PATH = 32;
|
|
37
42
|
const clean = (value) => (typeof value === 'string' ? value.trim() : '');
|
|
38
43
|
const isRecord = (value) => Boolean(value) && typeof value === 'object' && !Array.isArray(value);
|
|
@@ -40,38 +45,91 @@ const isRecord = (value) => Boolean(value) && typeof value === 'object' && !Arra
|
|
|
40
45
|
const agentOwned = (record) =>
|
|
41
46
|
clean(record?.owner).toLowerCase() === 'agent' || clean(record?.visibility).toLowerCase() === 'agent-only';
|
|
42
47
|
|
|
43
|
-
/** The session that
|
|
44
|
-
*
|
|
48
|
+
/** The session that spawned `record`, or '' for a top-level session (a task
|
|
49
|
+
* session a bot created is top-level, like any coding Lead). */
|
|
45
50
|
function parentOf(record) {
|
|
46
|
-
|
|
47
|
-
return clean(record?.taskOrigin?.sessionId);
|
|
51
|
+
return agentOwned(record) ? clean(record.parentSessionId) || clean(record.ownerSessionId) : '';
|
|
48
52
|
}
|
|
49
53
|
|
|
50
54
|
/** The step a new session adds to its parent's path. */
|
|
51
|
-
|
|
52
|
-
return agentOwned(record) ? { kind: 'agent', agent: clean(record.agent) } : { kind: 'task' };
|
|
53
|
-
}
|
|
55
|
+
const stepOf = (record) => ({ kind: 'agent', agent: clean(record.agent) });
|
|
54
56
|
|
|
57
|
+
/** A recorded delegation, or null when it is malformed or carries a step that
|
|
58
|
+
* is not an agent (a stored task step: derived again, never trusted). */
|
|
55
59
|
function validDelegation(value) {
|
|
56
60
|
if (!isRecord(value) || !clean(value.rootSessionId) || !VIA.has(value.via)) return null;
|
|
57
61
|
if (!Array.isArray(value.path) || value.path.length === 0 || value.path.length > MAX_PATH) return null;
|
|
58
|
-
if (value.
|
|
62
|
+
if (!value.path.every((step) => step?.kind === 'agent')) return null;
|
|
59
63
|
return value;
|
|
60
64
|
}
|
|
61
65
|
|
|
62
|
-
/** A failed rebind leaves `{ unresolved: true }` instead of a delegation: an
|
|
63
|
-
* explicit "no root", so the legacy backfill cannot derive one again from a
|
|
64
|
-
* parent that still holds a run. */
|
|
65
|
-
const UNRESOLVED = Object.freeze({ unresolved: true });
|
|
66
|
-
const isUnresolvedMark = (value) => isRecord(value) && value.unresolved === true;
|
|
67
|
-
|
|
68
66
|
/** The recorded delegation of `record`, else its legacy backfill; null when
|
|
69
|
-
* it has none
|
|
67
|
+
* it has none and none can be derived. */
|
|
70
68
|
function delegationOfRecord(id, record, depth) {
|
|
71
|
-
|
|
69
|
+
stampRun(id, record);
|
|
72
70
|
return validDelegation(record.delegation) || backfillOf(id, record, depth);
|
|
73
71
|
}
|
|
74
72
|
|
|
73
|
+
const RUN_TASK_SOURCE = /^agent:([A-Za-z0-9_-]+)@run$/;
|
|
74
|
+
const runStamp = (kind, agentId, name) =>
|
|
75
|
+
clean(agentId)
|
|
76
|
+
? { kind: kind === 'webhook' ? 'webhook' : 'schedule', agentId: clean(agentId), name: String(name || '') }
|
|
77
|
+
: null;
|
|
78
|
+
|
|
79
|
+
/** The run a record from before the `run` stamp was started by, from what it
|
|
80
|
+
* recorded itself: an old `via: 'run'` delegation, a host-set `@run` task
|
|
81
|
+
* source, else — a sub-agent that recorded no delegation — its parent's run. */
|
|
82
|
+
function legacyRunOf(id, record, depth) {
|
|
83
|
+
const old = record.delegation;
|
|
84
|
+
if (isRecord(old) && old.via === 'run' && isRecord(old.run)) {
|
|
85
|
+
return runStamp(old.run.kind, old.rootAgentId || agentIdOfHomeSession(old.rootSessionId), old.run.name);
|
|
86
|
+
}
|
|
87
|
+
const taskBot =
|
|
88
|
+
!agentOwned(record) && clean(record.sourceType) === 'lead'
|
|
89
|
+
? RUN_TASK_SOURCE.exec(clean(record.sourceName))?.[1]
|
|
90
|
+
: '';
|
|
91
|
+
if (taskBot) return runStamp('schedule', taskBot, '');
|
|
92
|
+
const parent = parentOf(record);
|
|
93
|
+
if (!parent || parent === id || isRecord(old) || depth >= MAX_PATH) return null;
|
|
94
|
+
const parentRecord = loadRecord(parent);
|
|
95
|
+
return parentRecord ? stampRun(parent, parentRecord, depth + 1) : null;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/** The `run` of `record`: its stamp (`null` = attended), else the run it
|
|
99
|
+
* recorded before stamps existed, kept on the live record. */
|
|
100
|
+
function stampRun(id, record, depth = 0) {
|
|
101
|
+
if (record.run !== undefined) return isRecord(record.run) ? record.run : null;
|
|
102
|
+
const run = legacyRunOf(id, record, depth);
|
|
103
|
+
if (run && _liveSessions.get(id) === record) record.run = run;
|
|
104
|
+
return run;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/** The run stamped on session `sessionId` (human-gate/delegation.mjs), or null. */
|
|
108
|
+
export function runStampOf(sessionId) {
|
|
109
|
+
const id = clean(sessionId);
|
|
110
|
+
const record = id ? loadRecord(id) : null;
|
|
111
|
+
return record ? stampRun(id, record) : null;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/** The schedule/webhook run `sessionId` is, or inherited from the session that
|
|
115
|
+
* started it, as `{ kind, agentId, name }`; null otherwise (a room member's
|
|
116
|
+
* own session is no run here). */
|
|
117
|
+
function runOfSession(sessionId) {
|
|
118
|
+
const run = unattendedApprovalPort()?.runOf?.(sessionId);
|
|
119
|
+
return run && run.kind !== 'room' ? { kind: run.kind, agentId: run.agentId, name: String(run.name || '') } : null;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* The `run` to stamp on a session being created with `opts`: the run its
|
|
124
|
+
* creator (the spawning session, or the chat a task session was created from)
|
|
125
|
+
* is or inherited, else null. Work a run started stays the run's, however long
|
|
126
|
+
* ago the run ended; it is read from the creator, never from tool input.
|
|
127
|
+
*/
|
|
128
|
+
export function runForNewSession(opts = {}) {
|
|
129
|
+
const creator = parentOf(opts) || clean(opts.taskOrigin?.sessionId);
|
|
130
|
+
return creator && creator !== clean(opts.id) ? runOfSession(creator) : null;
|
|
131
|
+
}
|
|
132
|
+
|
|
75
133
|
function loadRecord(sessionId) {
|
|
76
134
|
try {
|
|
77
135
|
return loadSession(sessionId);
|
|
@@ -80,85 +138,35 @@ function loadRecord(sessionId) {
|
|
|
80
138
|
}
|
|
81
139
|
}
|
|
82
140
|
|
|
83
|
-
/**
|
|
84
|
-
*
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
if (run && run.kind !== 'room') {
|
|
90
|
-
return { rootAgentId: clean(run.agentId), via: 'run', run: { kind: run.kind, name: String(run.name || '') } };
|
|
91
|
-
}
|
|
92
|
-
const member = roomMemberOfSession(sessionId);
|
|
93
|
-
if (member) return { rootAgentId: member.agentId, via: 'room' };
|
|
94
|
-
const home = agentIdOfHomeSession(sessionId);
|
|
95
|
-
if (home) return { rootAgentId: home, via: 'home' };
|
|
96
|
-
if (!record || agentOwned(record)) return null;
|
|
97
|
-
// A Lead with host-set bot provenance (session-options taskOriginSuffix) is
|
|
98
|
-
// a bot's task session, never coding work: its root is that bot's chat.
|
|
99
|
-
const source = sourceTaskOf(record);
|
|
100
|
-
if (source === false) return null;
|
|
101
|
-
if (source) {
|
|
102
|
-
const task = { rootSessionId: agentHomeSessionId(source.bot), rootAgentId: source.bot, task: true };
|
|
103
|
-
if (source.from === 'home') return { ...task, via: 'home' };
|
|
104
|
-
if (source.from === 'run') return { ...task, via: 'run', run: { kind: 'schedule', name: '' } };
|
|
105
|
-
if (source.from === undefined) return { ...task, via: 'unknown' };
|
|
106
|
-
return null; // a room (which one is not recorded) or anything else: ambiguous
|
|
107
|
-
}
|
|
108
|
-
return { rootAgentId: '', via: 'coding' };
|
|
141
|
+
/** What a top-level session `sessionId` is to a child: a bot's own home chat
|
|
142
|
+
* or room member session ('bot', no record needed, the id names its agent),
|
|
143
|
+
* a record-bearing coding session ('coding'), else nothing. */
|
|
144
|
+
function viaOf(sessionId, record) {
|
|
145
|
+
if (roomMemberOfSession(sessionId) || agentIdOfHomeSession(sessionId)) return 'bot';
|
|
146
|
+
return record && !agentOwned(record) ? 'coding' : null;
|
|
109
147
|
}
|
|
110
148
|
|
|
111
|
-
/**
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
if (agentOwned(record) || clean(record?.sourceType) !== 'lead' || !source.startsWith('agent:')) return null;
|
|
116
|
-
const [bot, from, ...rest] = source.slice(6).split('@');
|
|
117
|
-
return AGENT_ID.test(bot) && !rest.length ? { bot, from } : false;
|
|
149
|
+
/** The root of a top-level `parent` for a child taking `step`. */
|
|
150
|
+
function rootFrom(parent, record, step) {
|
|
151
|
+
const via = viaOf(parent, record);
|
|
152
|
+
return via ? { rootSessionId: parent, via, path: [step] } : null;
|
|
118
153
|
}
|
|
119
154
|
|
|
120
|
-
/** The
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
if (!binding) return null;
|
|
124
|
-
const { task, ...root } = binding;
|
|
125
|
-
return { rootSessionId: parent, ...root, path: task ? [{ kind: 'task' }, step] : [step] };
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
/** The delegation a legacy `record` (id `id`, a parent link, none recorded)
|
|
129
|
-
* is given, derived now from what was recorded — its own host-set `@run`
|
|
130
|
-
* provenance, else its parent's record, which must exist — and kept on the
|
|
131
|
-
* live record; null when it cannot be derived. Never `via: 'home'`: whether
|
|
132
|
-
* an old record was started by the attended chat (or by a run that has
|
|
133
|
-
* ended since) is not recorded, so home ancestry becomes 'unknown' — that
|
|
134
|
-
* bot, never remembered. Only a session created with its `delegation` can be
|
|
135
|
-
* 'home'. */
|
|
155
|
+
/** The delegation a legacy `record` (id `id`, a parent link, none valid
|
|
156
|
+
* recorded) is given, derived now from its parent, and kept on the live
|
|
157
|
+
* record; null when it cannot be derived. */
|
|
136
158
|
function backfillOf(id, record, depth = 0) {
|
|
137
159
|
const parent = parentOf(record);
|
|
138
160
|
if (!parent || parent === id || depth >= MAX_PATH) return null;
|
|
139
|
-
const
|
|
161
|
+
const parentRecord = loadRecord(parent);
|
|
162
|
+
const step = stepOf(record);
|
|
140
163
|
let delegation = null;
|
|
141
|
-
if (
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
rootAgentId: own.bot,
|
|
146
|
-
via: 'run',
|
|
147
|
-
run: { kind: 'schedule', name: '' },
|
|
148
|
-
path: [{ kind: 'task' }],
|
|
149
|
-
};
|
|
164
|
+
if (parentOf(parentRecord)) {
|
|
165
|
+
const inherited = delegationOfRecord(parent, parentRecord, depth + 1);
|
|
166
|
+
if (!inherited || inherited.path.length >= MAX_PATH) return null;
|
|
167
|
+
delegation = { ...inherited, path: [...inherited.path, step] };
|
|
150
168
|
} else {
|
|
151
|
-
|
|
152
|
-
if (!parentRecord) return null;
|
|
153
|
-
const step = stepOf(record);
|
|
154
|
-
if (parentOf(parentRecord)) {
|
|
155
|
-
const inherited = delegationOfRecord(parent, parentRecord, depth + 1);
|
|
156
|
-
if (!inherited || inherited.path.length >= MAX_PATH) return null;
|
|
157
|
-
delegation = { ...inherited, path: [...inherited.path, step] };
|
|
158
|
-
} else {
|
|
159
|
-
delegation = rootFrom(parent, parentRecord, step, { legacy: true });
|
|
160
|
-
}
|
|
161
|
-
if (delegation?.via === 'home') delegation = { ...delegation, via: 'unknown' };
|
|
169
|
+
delegation = rootFrom(parent, parentRecord, step);
|
|
162
170
|
}
|
|
163
171
|
if (delegation && _liveSessions.get(id) === record) record.delegation = delegation;
|
|
164
172
|
return delegation;
|
|
@@ -166,9 +174,9 @@ function backfillOf(id, record, depth = 0) {
|
|
|
166
174
|
|
|
167
175
|
/**
|
|
168
176
|
* The `delegation` to record on a session being created with `opts` (its
|
|
169
|
-
* owner/visibility, parentSessionId/ownerSessionId
|
|
177
|
+
* owner/visibility, parentSessionId/ownerSessionId and agent), or
|
|
170
178
|
* null: none for a top-level session, none for one whose parent's root cannot
|
|
171
|
-
* be established (
|
|
179
|
+
* be established (it is no bot's session: nothing is asked or mirrored for it).
|
|
172
180
|
*/
|
|
173
181
|
export function delegationForNewSession(opts = {}) {
|
|
174
182
|
const parent = parentOf(opts);
|
|
@@ -189,42 +197,44 @@ function delegationUnder(parent, step) {
|
|
|
189
197
|
}
|
|
190
198
|
|
|
191
199
|
/**
|
|
192
|
-
* Session `callerSessionId` sends the
|
|
193
|
-
* (`agent send`, a spawn of its tag, a task-session send): from now
|
|
194
|
-
*
|
|
195
|
-
*
|
|
196
|
-
*
|
|
197
|
-
*
|
|
198
|
-
*
|
|
199
|
-
*
|
|
200
|
-
*
|
|
201
|
-
* nothing
|
|
202
|
-
* delegation) or the running turn kept its status. A caller whose root cannot
|
|
203
|
-
* be established leaves the record without one, which the gate fails closed on.
|
|
200
|
+
* Session `callerSessionId` sends the sub-agent or task session `sessionId`
|
|
201
|
+
* new work (`agent send`, a spawn of its tag, a task-session send): from now
|
|
202
|
+
* on it is run-stamped as it would have been created under the caller, and a
|
|
203
|
+
* sub-agent is rooted under the caller's root when one can be established; the
|
|
204
|
+
* record is saved, so a restart keeps it — work an unattended run started is
|
|
205
|
+
* attended when the chat later reuses it, and the reverse. The run is passed on
|
|
206
|
+
* whether or not a root resolves. A turn already running is never made a run
|
|
207
|
+
* mid-turn. Resolves true when the record changed; false when nothing applies
|
|
208
|
+
* (no record, neither a sub-agent nor a task session, no or the same caller,
|
|
209
|
+
* nothing different).
|
|
204
210
|
*/
|
|
205
211
|
export async function rebindDelegation(sessionId, callerSessionId) {
|
|
206
212
|
const id = clean(sessionId);
|
|
207
213
|
const caller = clean(callerSessionId);
|
|
208
214
|
const record = id ? loadRecord(id) : null;
|
|
209
|
-
if (!record || record.closed === true || !caller || caller === id
|
|
210
|
-
const
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
+
if (!record || record.closed === true || !caller || caller === id) return false;
|
|
216
|
+
const delegated = Boolean(parentOf(record));
|
|
217
|
+
if (!delegated && !record.taskOrigin) return false;
|
|
218
|
+
const next = delegated ? delegationUnder(caller, stepOf(record)) : null;
|
|
219
|
+
const run = runOfSession(caller);
|
|
220
|
+
const current = stampRun(id, record);
|
|
221
|
+
const same = (a, b) => JSON.stringify(a ?? null) === JSON.stringify(b ?? null);
|
|
222
|
+
const reroot = Boolean(next) && !same(validDelegation(record.delegation), next);
|
|
223
|
+
if (!reroot && same(current, run)) return false;
|
|
224
|
+
if (run && !current && isTurnInFlight(runtimeState.get(id))) return false;
|
|
225
|
+
if (reroot) record.delegation = next;
|
|
226
|
+
if (run || current) record.run = run; // null = attended: legacy provenance no longer applies
|
|
215
227
|
await saveSessionAsync(record, { expectedGeneration: record.generation });
|
|
216
228
|
return true;
|
|
217
229
|
}
|
|
218
230
|
|
|
219
|
-
/** `{ state: '
|
|
220
|
-
* `{ state: '
|
|
221
|
-
*
|
|
231
|
+
/** `{ state: 'resolved', ...delegation }` for a sub-agent whose root is known,
|
|
232
|
+
* else `{ state: 'top' }`: a top-level session, one with no record, or one
|
|
233
|
+
* with a parent link and no derivable root (no bot's session either). */
|
|
222
234
|
export function delegationOf(sessionId) {
|
|
223
235
|
const id = clean(sessionId);
|
|
224
236
|
const record = id ? loadRecord(id) : null;
|
|
225
|
-
|
|
226
|
-
const
|
|
227
|
-
|
|
228
|
-
const delegation = parent === id ? null : delegationOfRecord(id, record);
|
|
229
|
-
return delegation ? { state: 'resolved', ...delegation } : { state: 'unresolved' };
|
|
237
|
+
const parent = record ? parentOf(record) : '';
|
|
238
|
+
const delegation = parent && parent !== id ? delegationOfRecord(id, record) : null;
|
|
239
|
+
return delegation ? { state: 'resolved', ...delegation } : { state: 'top' };
|
|
230
240
|
}
|
|
@@ -9,10 +9,12 @@
|
|
|
9
9
|
// actingBotId); an ordinary coding session's outbound call passes with the
|
|
10
10
|
// hook decision unchanged. Other surfaces (group rooms) call it with their own
|
|
11
11
|
// decision to get the same outbound rule. After the user answered,
|
|
12
|
-
// recordHumanDecision stores a "don't ask again" grant and the audit line.
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
|
|
12
|
+
// recordHumanDecision stores a "don't ask again" grant and the audit line.
|
|
13
|
+
// Schedule and webhook runs never ask (run-policy.mjs): ordinary actions are
|
|
14
|
+
// allowed, payments and permanent deletes denied. Group-room members register
|
|
15
|
+
// a port here (session-runtime/held-requests.mjs) that turns their asks into
|
|
16
|
+
// held requests when no approval card is attached.
|
|
17
|
+
import { MIXY_AGENT_ID, agentIdOfHomeSession } from '../agent-home.mjs';
|
|
16
18
|
import { serverConnector } from '../../mcp/server-connectors.mjs';
|
|
17
19
|
import { readAgentDefinitionKind } from '../../../../shared/agent-kind.mjs';
|
|
18
20
|
import { isContactAgentId } from '../../../../shared/agent-route-config.mjs';
|
|
@@ -37,8 +39,8 @@ export const BLOCKED_ACTION_REASON = "This agent's permission blocks this action
|
|
|
37
39
|
* payments and deletes never. */
|
|
38
40
|
const outboundRemember = (category) => (isRememberableAction(category) ? ['once', 'agent'] : ['once']);
|
|
39
41
|
|
|
40
|
-
// The unattended runs' port lives in unattended-port.mjs
|
|
41
|
-
//
|
|
42
|
+
// The unattended runs' port lives in unattended-port.mjs; its setter and
|
|
43
|
+
// getter are re-exported here.
|
|
42
44
|
export { setUnattendedApprovalPort, unattendedApprovalPort };
|
|
43
45
|
|
|
44
46
|
/** The agent a session is bound to by itself: its unattended run's owner, a
|
|
@@ -49,36 +51,24 @@ function ownBoundAgentId(sessionId) {
|
|
|
49
51
|
return roomMemberOfSession(sessionId)?.agentId || agentIdOfHomeSession(sessionId) || '';
|
|
50
52
|
}
|
|
51
53
|
|
|
52
|
-
/** The agent a session is bound to: its own binding, else — a sub-agent at
|
|
53
|
-
* any depth, a task session a bot created — the root recorded on it when it
|
|
54
|
-
* was created (delegation.mjs); '' for a coding Lead and every agent under
|
|
55
|
-
* it, and for a delegated session whose root is unknown (see isUnresolved). */
|
|
56
|
-
function boundAgentId(sessionId) {
|
|
57
|
-
const own = ownBoundAgentId(sessionId);
|
|
58
|
-
if (own) return own;
|
|
59
|
-
const delegation = delegationOf(sessionId);
|
|
60
|
-
return delegation.state === 'resolved' ? delegation.rootAgentId : '';
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/** A delegated session whose root could not be established: it may act for a
|
|
64
|
-
* bot, so the gate fails closed (outbound asks, nothing is remembered). */
|
|
65
|
-
const isUnresolved = (sessionId) => !ownBoundAgentId(sessionId) && delegationOf(sessionId).state === 'unresolved';
|
|
66
|
-
|
|
67
54
|
/** The agent a session acts for: its unattended run's owner, a room member,
|
|
68
|
-
* a home thread's agent, else Mixy.
|
|
55
|
+
* a home thread's agent, else Mixy. Work a schedule/webhook run started (a
|
|
56
|
+
* sub-agent, a task session) acts for the run's owner; a chat's sub-agent, a
|
|
57
|
+
* chat-created task session and a coding Lead are bound to nothing. */
|
|
69
58
|
export function agentIdForSession(sessionId) {
|
|
70
|
-
return
|
|
59
|
+
return ownBoundAgentId(sessionId) || MIXY_AGENT_ID;
|
|
71
60
|
}
|
|
72
61
|
|
|
73
62
|
/** The bot a session acts for, or '' when none: Mixy in her own home thread
|
|
74
63
|
* (or her unattended run / room member session), or a contact agent (`kind:
|
|
75
64
|
* bot`, isContactAgentId) in its home thread, room member session or
|
|
76
|
-
* unattended run
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
* sub-agent
|
|
80
|
-
|
|
81
|
-
|
|
65
|
+
* unattended run. Work a schedule/webhook run started (a sub-agent, a task
|
|
66
|
+
* session) resolves to the run's bot (ownBoundAgentId → runOf). A coding Lead
|
|
67
|
+
* (also id 'lead'), a task session a bot created in a chat, their workflow
|
|
68
|
+
* agents and every sub-agent of a chat (also a bot's) are bound to nothing
|
|
69
|
+
* here, so they are no bot. */
|
|
70
|
+
export function actingBotId(sessionId) {
|
|
71
|
+
const id = ownBoundAgentId(sessionId);
|
|
82
72
|
if (!id) return '';
|
|
83
73
|
if (id === MIXY_AGENT_ID) return id;
|
|
84
74
|
const kind = readAgentDefinitionKind({ dataDir: resolvePluginData(), shippedRoot: mixdogRoot(), id });
|
|
@@ -92,44 +82,24 @@ function actingBotId(sessionId) {
|
|
|
92
82
|
* entry: none is offered to Mixy, a Lead or a workflow agent. */
|
|
93
83
|
export function actingContactBotId(sessionId) {
|
|
94
84
|
const id = actingBotId(sessionId);
|
|
95
|
-
|
|
96
|
-
// (rememberSurfaceOf). A room member, an unattended run (a schedule, a
|
|
97
|
-
// webhook) and work they started act for the bot in a session that is not its chat.
|
|
98
|
-
return id && id !== MIXY_AGENT_ID && rememberSurfaceOf(sessionId) === agentHomeSessionId(id) ? id : '';
|
|
85
|
+
return id && id !== MIXY_AGENT_ID ? id : '';
|
|
99
86
|
}
|
|
100
87
|
|
|
101
|
-
|
|
102
|
-
* remembered ("don't ask again", "always allow"): the bot's home chat when
|
|
103
|
-
* the request lives there, or surfaces there because the work was started
|
|
104
|
-
* from that attended chat; '' otherwise (a room, a run, a coding Lead, an
|
|
105
|
-
* unresolved delegation). The approval queue honours a remembering answer
|
|
106
|
-
* only from that session (tui/session/tool-approval.mjs). */
|
|
107
|
-
export function rememberSurfaceOf(sessionId) {
|
|
108
|
-
// A schedule/webhook running in the home itself is not the attended chat.
|
|
109
|
-
if (unattendedApprovalPort()?.runOf?.(sessionId)) return '';
|
|
110
|
-
if (agentIdOfHomeSession(sessionId)) return sessionId;
|
|
111
|
-
if (ownBoundAgentId(sessionId)) return '';
|
|
112
|
-
const delegation = delegationOf(sessionId);
|
|
113
|
-
return delegation.state === 'resolved' && delegation.via === 'home' ? delegation.rootSessionId : '';
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
// Chain tokens the desktop translates (ApprovalCard approvalChainLabel).
|
|
88
|
+
// Chain token the desktop translates (ApprovalCard approvalChainLabel).
|
|
117
89
|
const LEAD_NAME = 'Lead';
|
|
118
|
-
const TASK_SESSION_NAME = 'Task session';
|
|
119
90
|
|
|
120
|
-
/** Where a
|
|
121
|
-
*
|
|
122
|
-
*
|
|
123
|
-
*
|
|
124
|
-
* "
|
|
125
|
-
*
|
|
91
|
+
/** Where a sub-agent's approval cards also surface, and who is asking:
|
|
92
|
+
* `{ sessionId, chain }` — the session it works under (a coding Lead, a
|
|
93
|
+
* bot-created task session, a bot's home chat or room member session) and
|
|
94
|
+
* the names from there down to the asker ("Lead › Reviewer", "사무관 ›
|
|
95
|
+
* Worker"). Only where the card shows: no bot identity, grant or remember
|
|
96
|
+
* scope follows from it. Null for a top-level session. */
|
|
126
97
|
export function approvalSurface(sessionId) {
|
|
127
98
|
const delegation = delegationOf(sessionId);
|
|
128
99
|
if (delegation.state !== 'resolved') return null;
|
|
129
|
-
const
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
}
|
|
100
|
+
const bot = delegation.via === 'bot' ? ownBoundAgentId(delegation.rootSessionId) : '';
|
|
101
|
+
const chain = [bot ? agentDisplayName(bot) || bot : LEAD_NAME];
|
|
102
|
+
for (const step of delegation.path) chain.push(agentDisplayName(step.agent) || step.agent);
|
|
133
103
|
return { sessionId: delegation.rootSessionId, chain };
|
|
134
104
|
}
|
|
135
105
|
|
|
@@ -188,10 +158,7 @@ async function describeEmails(call, outbound, ctx) {
|
|
|
188
158
|
export async function humanGateDecision(call, decision, ctx = {}) {
|
|
189
159
|
const action = actionOf(decision);
|
|
190
160
|
if (action === 'deny' || action === 'block') return { decision, request: null, gate: null };
|
|
191
|
-
|
|
192
|
-
// and remember surface are unknown — every outbound call asks, once only.
|
|
193
|
-
const unresolved = isUnresolved(ctx.sessionId);
|
|
194
|
-
const agentId = unresolved ? '' : agentIdForSession(ctx.sessionId);
|
|
161
|
+
const agentId = agentIdForSession(ctx.sessionId);
|
|
195
162
|
const annotations = ctx.annotations ?? (await mcpAnnotations(call?.name, ctx.mcpScopeId));
|
|
196
163
|
let classified = classifyOutboundCall({ name: call?.name, args: call?.args, annotations });
|
|
197
164
|
const remoteDelete = isRemoteDeleteInRun({ name: call?.name, annotations }, classified);
|
|
@@ -215,7 +182,7 @@ export async function humanGateDecision(call, decision, ctx = {}) {
|
|
|
215
182
|
if (remoteDelete && classified?.category !== 'delete' && classified?.category !== 'payment') {
|
|
216
183
|
classified = classifyAsDelete({ name: call?.name, args: call?.args });
|
|
217
184
|
}
|
|
218
|
-
const outbound = classified &&
|
|
185
|
+
const outbound = classified && actingBotId(ctx.sessionId) ? classified : null;
|
|
219
186
|
if (!outbound) {
|
|
220
187
|
if (action !== 'ask') return { decision, request: null, gate: null };
|
|
221
188
|
return {
|
|
@@ -239,14 +206,10 @@ export async function humanGateDecision(call, decision, ctx = {}) {
|
|
|
239
206
|
},
|
|
240
207
|
remember: ['once'],
|
|
241
208
|
};
|
|
242
|
-
// "Don't ask again"
|
|
243
|
-
|
|
244
|
-
if (rememberAt && isRememberableAction(outbound.category)) {
|
|
245
|
-
request.remember = outboundRemember(outbound.category);
|
|
246
|
-
request.rememberAt = rememberAt;
|
|
247
|
-
}
|
|
209
|
+
// "Don't ask again" is the bot's permission.
|
|
210
|
+
request.remember = outboundRemember(outbound.category);
|
|
248
211
|
const store = ctx.store || (await humanGateStore());
|
|
249
|
-
const mode =
|
|
212
|
+
const mode = await store.modeFor({ agentId, action: outbound.category });
|
|
250
213
|
const base = decision && typeof decision === 'object' ? decision : {};
|
|
251
214
|
if (mode === 'block') {
|
|
252
215
|
await store.recordAudit({ ...gate, decision: 'blocked', device: '' });
|
|
@@ -285,8 +248,8 @@ export async function recordHumanDecision(gate, approval, { store } = {}) {
|
|
|
285
248
|
let decision = approval?.response || (approval?.approved === true ? 'approve' : 'deny');
|
|
286
249
|
if (approval?.timedOut) decision = 'timeout';
|
|
287
250
|
const device = typeof approval?.device === 'string' ? approval.device : '';
|
|
288
|
-
// A scope the request did not offer (
|
|
289
|
-
//
|
|
251
|
+
// A scope the request did not offer (a payment or permanent delete is only
|
|
252
|
+
// ever answered once) stores nothing.
|
|
290
253
|
const offered = !Array.isArray(gate.remember) || gate.remember.includes(approval?.remember);
|
|
291
254
|
if (approval?.approved === true && gate.action && offered) {
|
|
292
255
|
await target.grant({ agentId: gate.agentId, action: gate.action, scope: approval.remember, device });
|
|
@@ -84,8 +84,6 @@ export function humanRequestFields(input = {}) {
|
|
|
84
84
|
const fields = { remember: rememberScopes(input.remember) };
|
|
85
85
|
// The agent the request acts for (its name on the card and the remembered grant).
|
|
86
86
|
if (text(input.agentId)) fields.agentId = text(input.agentId);
|
|
87
|
-
// The one session a remembering answer may come from (gate.mjs rememberSurfaceOf).
|
|
88
|
-
if (text(input.rememberAt)) fields.rememberAt = text(input.rememberAt);
|
|
89
87
|
if (kind === 'outbound' && isRecord(input.outbound)) {
|
|
90
88
|
const outbound = input.outbound;
|
|
91
89
|
const details = isRecord(outbound.details) ? outbound.details : {};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// session/human-gate/run-policy.mjs
|
|
2
2
|
// Schedule and webhook runs never ask. Saving a schedule or webhook is the
|
|
3
|
-
// user's explicit grant for its runs (and for the work they start: sub-agents
|
|
4
|
-
//
|
|
3
|
+
// user's explicit grant for its runs (and for the work they start: sub-agents):
|
|
4
|
+
// outbound actions and ordinary tool approvals are
|
|
5
5
|
// allowed without a card, a held row or a push, inside the bot's own
|
|
6
6
|
// permissions (a `block` is applied before any ask, gate.mjs). Payments and
|
|
7
7
|
// permanent deletes (the action kinds that can never be remembered) are never
|
|
@@ -117,9 +117,9 @@ export function compactionSummaryPlan({
|
|
|
117
117
|
return { mode, warm, steps };
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
-
// The summary request on one route: the conversation alone (earlier summary
|
|
121
|
-
//
|
|
122
|
-
// cached context. Its input budget belongs to its OWN model, split into
|
|
120
|
+
// The summary request on one route: the conversation alone (earlier summary,
|
|
121
|
+
// dialogue, runtime conversation rows and one bounded line per tool call;
|
|
122
|
+
// skills and injections excluded), never the cached context. Its input budget belongs to its OWN model, split into
|
|
123
123
|
// batches when the conversation is larger, whereas the rebuilt conversation
|
|
124
124
|
// must fit the original session's target/window.
|
|
125
125
|
function summarizeConversation(target, ctx) {
|
|
@@ -159,7 +159,6 @@ function summarizeConversation(target, ctx) {
|
|
|
159
159
|
fast: target.fast,
|
|
160
160
|
timeoutMs: compactPolicy.handoffTimeoutMs,
|
|
161
161
|
force: true,
|
|
162
|
-
filterOldHistoryForIngest: true,
|
|
163
162
|
}
|
|
164
163
|
);
|
|
165
164
|
}
|
|
@@ -338,8 +337,13 @@ export async function runFreshContextCompact({
|
|
|
338
337
|
} = {}) {
|
|
339
338
|
const startedAt = Date.now();
|
|
340
339
|
signal?.throwIfAborted();
|
|
341
|
-
const { contextWindow, hardBudget,
|
|
342
|
-
|
|
340
|
+
const { contextWindow, hardBudget, conversationTokens, conversationThresholdTokens } = freshContextBudget({
|
|
341
|
+
compactPolicy,
|
|
342
|
+
sessionRef,
|
|
343
|
+
provider,
|
|
344
|
+
compactBudgetTokens,
|
|
345
|
+
messages,
|
|
346
|
+
});
|
|
343
347
|
const summaryTriggered = conversationTokens >= conversationThresholdTokens;
|
|
344
348
|
const buildOptions = freshContextBuildOptions(
|
|
345
349
|
{ compactPolicy, sessionId, goalReminderText, activeTurn, referenceLatestAttachments },
|
|
@@ -383,7 +387,9 @@ export async function runFreshContextCompact({
|
|
|
383
387
|
compactBudgetTokens,
|
|
384
388
|
hardBudget,
|
|
385
389
|
contextWindow,
|
|
386
|
-
|
|
390
|
+
// What the summary is written from: the measured conversation plus one
|
|
391
|
+
// bounded line per tool call (conversationCompactionInput).
|
|
392
|
+
conversationInput: conversationCompactionInput(messages, { summary: true }),
|
|
387
393
|
},
|
|
388
394
|
plan
|
|
389
395
|
);
|