open-multi-agent-kit 0.96.1 → 0.96.2
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 +41 -0
- package/README.md +12 -2
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +1 -0
- package/dist/cli/args.js.map +1 -1
- package/dist/commands/resource-doctor-cli.d.ts +22 -0
- package/dist/commands/resource-doctor-cli.d.ts.map +1 -0
- package/dist/commands/resource-doctor-cli.js +98 -0
- package/dist/commands/resource-doctor-cli.js.map +1 -0
- package/dist/core/agent-session.d.ts +37 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +289 -5
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/completion-sound.d.ts +109 -0
- package/dist/core/completion-sound.d.ts.map +1 -0
- package/dist/core/completion-sound.js +165 -0
- package/dist/core/completion-sound.js.map +1 -0
- package/dist/core/context-budget-system-prompt-items.d.ts.map +1 -1
- package/dist/core/context-budget-system-prompt-items.js +2 -2
- package/dist/core/context-budget-system-prompt-items.js.map +1 -1
- package/dist/core/host-resource-probe.d.ts +63 -0
- package/dist/core/host-resource-probe.d.ts.map +1 -0
- package/dist/core/host-resource-probe.js +126 -0
- package/dist/core/host-resource-probe.js.map +1 -0
- package/dist/core/host-resource-snapshot.d.ts +54 -0
- package/dist/core/host-resource-snapshot.d.ts.map +1 -0
- package/dist/core/host-resource-snapshot.js +139 -0
- package/dist/core/host-resource-snapshot.js.map +1 -0
- package/dist/core/prompt-settlement.d.ts +81 -0
- package/dist/core/prompt-settlement.d.ts.map +1 -0
- package/dist/core/prompt-settlement.js +84 -0
- package/dist/core/prompt-settlement.js.map +1 -0
- package/dist/core/provider-resilience.d.ts.map +1 -1
- package/dist/core/provider-resilience.js +1 -1
- package/dist/core/provider-resilience.js.map +1 -1
- package/dist/core/provider-retry.d.ts +7 -0
- package/dist/core/provider-retry.d.ts.map +1 -1
- package/dist/core/provider-retry.js +24 -0
- package/dist/core/provider-retry.js.map +1 -1
- package/dist/core/provider-usage.d.ts +15 -2
- package/dist/core/provider-usage.d.ts.map +1 -1
- package/dist/core/provider-usage.js +110 -2
- package/dist/core/provider-usage.js.map +1 -1
- package/dist/core/reasoning-router-resolver.d.ts.map +1 -1
- package/dist/core/reasoning-router-resolver.js +1 -1
- package/dist/core/reasoning-router-resolver.js.map +1 -1
- package/dist/core/resource-admission-config.d.ts +55 -0
- package/dist/core/resource-admission-config.d.ts.map +1 -0
- package/dist/core/resource-admission-config.js +97 -0
- package/dist/core/resource-admission-config.js.map +1 -0
- package/dist/core/resource-admission.d.ts +81 -0
- package/dist/core/resource-admission.d.ts.map +1 -0
- package/dist/core/resource-admission.js +128 -0
- package/dist/core/resource-admission.js.map +1 -0
- package/dist/core/resource-governor-format.d.ts +50 -0
- package/dist/core/resource-governor-format.d.ts.map +1 -0
- package/dist/core/resource-governor-format.js +113 -0
- package/dist/core/resource-governor-format.js.map +1 -0
- package/dist/core/resource-governor-settings.d.ts +56 -0
- package/dist/core/resource-governor-settings.d.ts.map +1 -0
- package/dist/core/resource-governor-settings.js +89 -0
- package/dist/core/resource-governor-settings.js.map +1 -0
- package/dist/core/resource-observation-journal.d.ts +74 -0
- package/dist/core/resource-observation-journal.d.ts.map +1 -0
- package/dist/core/resource-observation-journal.js +198 -0
- package/dist/core/resource-observation-journal.js.map +1 -0
- package/dist/core/resource-safety-gate.d.ts +54 -0
- package/dist/core/resource-safety-gate.d.ts.map +1 -0
- package/dist/core/resource-safety-gate.js +51 -0
- package/dist/core/resource-safety-gate.js.map +1 -0
- package/dist/core/run-journal.d.ts.map +1 -1
- package/dist/core/run-journal.js +13 -1
- package/dist/core/run-journal.js.map +1 -1
- package/dist/core/run-resource-lease.d.ts +73 -0
- package/dist/core/run-resource-lease.d.ts.map +1 -0
- package/dist/core/run-resource-lease.js +78 -0
- package/dist/core/run-resource-lease.js.map +1 -0
- package/dist/core/session-bash-service.d.ts +12 -0
- package/dist/core/session-bash-service.d.ts.map +1 -1
- package/dist/core/session-bash-service.js +14 -0
- package/dist/core/session-bash-service.js.map +1 -1
- package/dist/core/session-system-prompt.d.ts +2 -0
- package/dist/core/session-system-prompt.d.ts.map +1 -1
- package/dist/core/session-system-prompt.js +2 -0
- package/dist/core/session-system-prompt.js.map +1 -1
- package/dist/core/session-termination.d.ts +7 -2
- package/dist/core/session-termination.d.ts.map +1 -1
- package/dist/core/session-termination.js +29 -1
- package/dist/core/session-termination.js.map +1 -1
- package/dist/core/settings-manager.d.ts +12 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +36 -0
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +1 -0
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/core/subagent-lane-launcher.d.ts +64 -0
- package/dist/core/subagent-lane-launcher.d.ts.map +1 -0
- package/dist/core/subagent-lane-launcher.js +107 -0
- package/dist/core/subagent-lane-launcher.js.map +1 -0
- package/dist/core/system-cpu-sampler.d.ts +45 -0
- package/dist/core/system-cpu-sampler.d.ts.map +1 -0
- package/dist/core/system-cpu-sampler.js +95 -0
- package/dist/core/system-cpu-sampler.js.map +1 -0
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +5 -8
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/workload-classifier.d.ts +32 -0
- package/dist/core/workload-classifier.d.ts.map +1 -0
- package/dist/core/workload-classifier.js +66 -0
- package/dist/core/workload-classifier.js.map +1 -0
- package/dist/core/workload-family-matcher.d.ts +3 -0
- package/dist/core/workload-family-matcher.d.ts.map +1 -0
- package/dist/core/workload-family-matcher.js +126 -0
- package/dist/core/workload-family-matcher.js.map +1 -0
- package/dist/core/workload-permit-pool.d.ts +78 -0
- package/dist/core/workload-permit-pool.d.ts.map +1 -0
- package/dist/core/workload-permit-pool.js +138 -0
- package/dist/core/workload-permit-pool.js.map +1 -0
- package/dist/core/workload-shard-executor.d.ts +68 -0
- package/dist/core/workload-shard-executor.d.ts.map +1 -0
- package/dist/core/workload-shard-executor.js +156 -0
- package/dist/core/workload-shard-executor.js.map +1 -0
- package/dist/core/workload-shard-plan.d.ts +81 -0
- package/dist/core/workload-shard-plan.d.ts.map +1 -0
- package/dist/core/workload-shard-plan.js +183 -0
- package/dist/core/workload-shard-plan.js.map +1 -0
- package/dist/core/workload-shard-runner.d.ts +11 -0
- package/dist/core/workload-shard-runner.d.ts.map +1 -0
- package/dist/core/workload-shard-runner.js +98 -0
- package/dist/core/workload-shard-runner.js.map +1 -0
- package/dist/core/workload-shard-store.d.ts +44 -0
- package/dist/core/workload-shard-store.d.ts.map +1 -0
- package/dist/core/workload-shard-store.js +189 -0
- package/dist/core/workload-shard-store.js.map +1 -0
- package/dist/core/workload-sharders.d.ts +47 -0
- package/dist/core/workload-sharders.d.ts.map +1 -0
- package/dist/core/workload-sharders.js +162 -0
- package/dist/core/workload-sharders.js.map +1 -0
- package/dist/core/workload-shell-scan.d.ts +12 -0
- package/dist/core/workload-shell-scan.d.ts.map +1 -0
- package/dist/core/workload-shell-scan.js +79 -0
- package/dist/core/workload-shell-scan.js.map +1 -0
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +6 -0
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +4 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +81 -0
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/docs/providers.md +1 -1
- package/docs/sdk.md +4 -0
- package/docs/settings.md +64 -2
- package/docs/skills.md +16 -0
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/subagent/agent-capability-router.test.ts +7 -0
- package/examples/extensions/subagent/domain-profiles.ts +0 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/npm-shrinkwrap.json +18 -18
- package/package.json +7 -9
|
@@ -44,6 +44,7 @@ import { ExtensionRunner, wrapRegisteredTools, } from "./extensions/index.js";
|
|
|
44
44
|
import { emitSessionShutdownEvent } from "./extensions/runner.js";
|
|
45
45
|
import { assertTextChatModelForCompletion } from "./grok-harness.js";
|
|
46
46
|
import { grokPlaybookAppendForProvider } from "./grok-playbook.js";
|
|
47
|
+
import { captureHostResourceSnapshot } from "./host-resource-snapshot.js";
|
|
47
48
|
import { decideLoadoutAccess } from "./loadout-access-policy.js";
|
|
48
49
|
import { loadMcpServerConfigs } from "./mcp/config.js";
|
|
49
50
|
import { McpManager } from "./mcp/manager.js";
|
|
@@ -53,6 +54,7 @@ import { TurnMetricsSink } from "./turn-metrics.js";
|
|
|
53
54
|
const DISABLED_ENV_VALUES = new Set(["0", "false", "off", "disable", "disabled"]);
|
|
54
55
|
const MAX_OVERFLOW_RECOVERY_ATTEMPTS = 2;
|
|
55
56
|
const OVERFLOW_RECOVERY_EMERGENCY_TOKENS = 4_096;
|
|
57
|
+
const MAX_RESOURCE_OBSERVATION_JOURNALS = 32;
|
|
56
58
|
function isDisabledEnvValue(value) {
|
|
57
59
|
return value !== undefined && DISABLED_ENV_VALUES.has(value.trim().toLowerCase());
|
|
58
60
|
}
|
|
@@ -75,6 +77,7 @@ import { selectContextFilesForModel } from "./model-prompt-policy.js";
|
|
|
75
77
|
import { findExactModelReferenceMatch } from "./model-resolver.js";
|
|
76
78
|
import { computePromptTokenBudget } from "./prompt-budget.js";
|
|
77
79
|
import { classifyPromptCacheTransition } from "./prompt-cache.js";
|
|
80
|
+
import { createPromptSettlementState, reducePromptSettlement, settlePromptIfReady, } from "./prompt-settlement.js";
|
|
78
81
|
import { expandPromptTemplate } from "./prompt-templates.js";
|
|
79
82
|
import { isQuotaExhaustionMessage, isStickySafetyModel, pickFailoverCandidate, resolveProviderResilience, shouldEjectStickySafetyModel, shouldHonorSafetyFailover, stickySafetyBlockMessage, } from "./provider-resilience.js";
|
|
80
83
|
import { computeRetryDelayMs, failoverModelKey, isFailoverTriggerError, isRetryableAssistantError, nextRetryAttempt, retryBudgetForAssistantError, } from "./provider-retry.js";
|
|
@@ -82,8 +85,13 @@ import { getBiasStepsForCell, parseRouterBiasSnapshot } from "./reasoning-router
|
|
|
82
85
|
import { classifyTaskV4, deriveRouterFeedbackFeaturesV4, resolveThinkingLevelV4WithUncertainty, TASK_CLASS_THINKING_LEVELS_V4, } from "./reasoning-router-v4.js";
|
|
83
86
|
import { redactSensitiveText, redactSensitiveTextForced } from "./redaction.js";
|
|
84
87
|
import { getRepositoryRouterLearningPaths } from "./repository-learning-scope.js";
|
|
88
|
+
import { decideResourceAdmission } from "./resource-admission.js";
|
|
89
|
+
import { resolveResourceGovernorSettings } from "./resource-governor-settings.js";
|
|
90
|
+
import { admissionObservationFacts, classificationObservationFacts, ResourceObservationJournal, settledObservationFacts, snapshotObservationFacts, soundObservationFacts, } from "./resource-observation-journal.js";
|
|
91
|
+
import { decideResourceSafetyGate, RESOURCE_PRESSURE_REQUIRED_ACTION } from "./resource-safety-gate.js";
|
|
85
92
|
import { appendRouterFeedbackRecord, ROUTER_FEEDBACK_LEVELS, } from "./router-feedback-collector.js";
|
|
86
93
|
import { RunJournalStore } from "./run-journal-store.js";
|
|
94
|
+
import { RunResourceLeaseController } from "./run-resource-lease.js";
|
|
87
95
|
import { SessionBashRuntime } from "./session-bash-runtime.js";
|
|
88
96
|
import { SessionBashService } from "./session-bash-service.js";
|
|
89
97
|
import { SessionCompactionService } from "./session-compaction-service.js";
|
|
@@ -98,6 +106,8 @@ import { createAllToolDefinitions } from "./tools/index.js";
|
|
|
98
106
|
import { createToolDefinitionFromAgentTool } from "./tools/tool-definition-wrapper.js";
|
|
99
107
|
import { createVerifiedBashOperations } from "./verified-bash-adapter.js";
|
|
100
108
|
import { resolveSessionWorkspaceScope } from "./verified-bash-runtime.js";
|
|
109
|
+
import { classifyWorkloadCommand } from "./workload-classifier.js";
|
|
110
|
+
import { WorkloadPermitError, WorkloadPermitPool } from "./workload-permit-pool.js";
|
|
101
111
|
/**
|
|
102
112
|
* Parse a skill block from message text.
|
|
103
113
|
* Returns null if the text doesn't contain a skill block.
|
|
@@ -356,6 +366,14 @@ export class AgentSession {
|
|
|
356
366
|
_runJournalStore;
|
|
357
367
|
_ownedSessionOwnerLease;
|
|
358
368
|
_activeRunId = null;
|
|
369
|
+
// Resource governor (roadmap M2): lease controller owns the temporary tool
|
|
370
|
+
// cap for governed runs; the last decision backs the §19.4 read-only API.
|
|
371
|
+
_resourceLeaseController;
|
|
372
|
+
_resourceObservations = null;
|
|
373
|
+
_resourceObservationJournals = new Map();
|
|
374
|
+
_latestResourcePromptRunId = null;
|
|
375
|
+
_lastResourceAdmission = null;
|
|
376
|
+
_workloadPermitPool;
|
|
359
377
|
_pendingRuntimeTerminationCause;
|
|
360
378
|
_activeRunToolTermination;
|
|
361
379
|
_lastTermination;
|
|
@@ -436,6 +454,7 @@ export class AgentSession {
|
|
|
436
454
|
isStreaming: () => this.isStreaming,
|
|
437
455
|
pushMessage: (message) => this.agent.state.messages.push(message),
|
|
438
456
|
appendMessage: (message) => this.sessionManager.appendMessage(message),
|
|
457
|
+
acquireResourcePermit: (command, signal) => this._acquireBashResourcePermit(command, signal),
|
|
439
458
|
});
|
|
440
459
|
this._compactionService = new SessionCompactionService({
|
|
441
460
|
sessionManager: this.sessionManager,
|
|
@@ -1627,7 +1646,15 @@ export class AgentSession {
|
|
|
1627
1646
|
this._promptCacheKey = nextKey;
|
|
1628
1647
|
this._promptCacheStablePrefixCharacters = boundary ?? 0;
|
|
1629
1648
|
}
|
|
1649
|
+
_getDefaultActiveSkills() {
|
|
1650
|
+
const trustedSkillNames = new Set(this._resourceLoader
|
|
1651
|
+
.getSkills()
|
|
1652
|
+
.skills.filter((skill) => skill.sourceInfo.scope === "user")
|
|
1653
|
+
.map((skill) => skill.name));
|
|
1654
|
+
return this.settingsManager.getDefaultActiveSkills().filter((name) => trustedSkillNames.has(name));
|
|
1655
|
+
}
|
|
1630
1656
|
_rebuildSystemPrompt(toolNames, model = this.model) {
|
|
1657
|
+
const defaultActiveSkills = this._getDefaultActiveSkills();
|
|
1631
1658
|
const assembled = assembleSessionSystemPrompt({
|
|
1632
1659
|
cwd: this._cwd,
|
|
1633
1660
|
toolNames,
|
|
@@ -1638,6 +1665,8 @@ export class AgentSession {
|
|
|
1638
1665
|
appendSystemPrompt: this._resourceLoader.getAppendSystemPrompt(),
|
|
1639
1666
|
providerAppend: grokPlaybookAppendForProvider(model?.provider),
|
|
1640
1667
|
skills: this._resourceLoader.getSkills().skills,
|
|
1668
|
+
activeSkillNames: defaultActiveSkills,
|
|
1669
|
+
activeSkillSource: defaultActiveSkills.length > 0 ? "settings" : undefined,
|
|
1641
1670
|
contextFiles: selectContextFilesForModel(this._resourceLoader.getAgentsFiles().agentsFiles, model),
|
|
1642
1671
|
contextBudget: this._getContextBudgetOptions(undefined, model),
|
|
1643
1672
|
});
|
|
@@ -1649,6 +1678,15 @@ export class AgentSession {
|
|
|
1649
1678
|
// Prompting
|
|
1650
1679
|
// =========================================================================
|
|
1651
1680
|
async _runAgentPrompt(messages) {
|
|
1681
|
+
// One identity per top-level run (§16.2): internal retries and
|
|
1682
|
+
// continuations inside this call share it, as does the resource lease.
|
|
1683
|
+
const promptRunId = `prompt-run-${randomUUID()}`;
|
|
1684
|
+
const startedAtEpochMs = Date.now();
|
|
1685
|
+
// Roadmap M2: the lease spans the whole run including internal retries
|
|
1686
|
+
// and continuations, so they share one admission decision (§8.3).
|
|
1687
|
+
const resourceLease = await this._beginResourceGovernedRun(promptRunId);
|
|
1688
|
+
const resourceObservations = this._resourceObservationJournals.get(promptRunId) ?? null;
|
|
1689
|
+
let outcome = "completed";
|
|
1652
1690
|
try {
|
|
1653
1691
|
await this.agent.prompt(messages);
|
|
1654
1692
|
while (await this._handlePostAgentRun()) {
|
|
@@ -1656,11 +1694,251 @@ export class AgentSession {
|
|
|
1656
1694
|
}
|
|
1657
1695
|
}
|
|
1658
1696
|
catch (error) {
|
|
1697
|
+
outcome =
|
|
1698
|
+
this._userAbortRequested || (error instanceof Error && /abort/i.test(error.message)) ? "aborted" : "failed";
|
|
1659
1699
|
this._publishRuntimeFailure(error);
|
|
1660
1700
|
throw error;
|
|
1661
1701
|
}
|
|
1662
1702
|
finally {
|
|
1703
|
+
if (resourceLease !== null) {
|
|
1704
|
+
// Generation-safe: a stale release after another run acquired the
|
|
1705
|
+
// lease is a no-op instead of clobbering the newer cap (§8.1).
|
|
1706
|
+
this._resourceLeaseController?.release(resourceLease);
|
|
1707
|
+
resourceObservations?.record("resource_lease_released_v1", { promptRunId });
|
|
1708
|
+
}
|
|
1663
1709
|
this._flushPendingBashMessages();
|
|
1710
|
+
// §16.4 (M4): settle only after every in-run continuation drained.
|
|
1711
|
+
this._emitPromptSettledIfReady({ promptRunId, startedAtEpochMs, outcome, resourceObservations });
|
|
1712
|
+
}
|
|
1713
|
+
}
|
|
1714
|
+
/**
|
|
1715
|
+
* Emit `prompt_settled` when the §16.4 conditions hold. Called exactly
|
|
1716
|
+
* once per promptRunId (from `_runAgentPrompt`'s finally), so the same
|
|
1717
|
+
* run can never emit twice; late-queued messages block emission
|
|
1718
|
+
* conservatively — the continuation run settles under its own id.
|
|
1719
|
+
* Settlement is a UX signal only and must never affect the run (§16.1).
|
|
1720
|
+
*/
|
|
1721
|
+
_emitPromptSettledIfReady(input) {
|
|
1722
|
+
try {
|
|
1723
|
+
let state = createPromptSettlementState(input.promptRunId, input.startedAtEpochMs);
|
|
1724
|
+
state = reducePromptSettlement(state, { kind: "terminal", outcome: input.outcome });
|
|
1725
|
+
if (this.isStreaming) {
|
|
1726
|
+
state = reducePromptSettlement(state, { kind: "tool", delta: 1 });
|
|
1727
|
+
}
|
|
1728
|
+
if (this.agent.hasQueuedMessages()) {
|
|
1729
|
+
state = reducePromptSettlement(state, { kind: "continuation", delta: 1 });
|
|
1730
|
+
}
|
|
1731
|
+
const settled = settlePromptIfReady(state, Date.now());
|
|
1732
|
+
if (settled.event !== null) {
|
|
1733
|
+
input.resourceObservations?.record("prompt_settled_v1", settledObservationFacts(settled.event));
|
|
1734
|
+
this._emit(settled.event);
|
|
1735
|
+
}
|
|
1736
|
+
}
|
|
1737
|
+
catch {
|
|
1738
|
+
// Never let settlement bookkeeping break a run.
|
|
1739
|
+
}
|
|
1740
|
+
}
|
|
1741
|
+
/**
|
|
1742
|
+
* Resource governor preflight for one top-level run (roadmap §8, §25.3 M2).
|
|
1743
|
+
*
|
|
1744
|
+
* - `off`: nothing; v0.96.1 observable behavior is preserved.
|
|
1745
|
+
* - `observe` (default): fire-and-forget probe records a decision for the
|
|
1746
|
+
* §19.4 read-only API; the cap never changes and the prompt is never
|
|
1747
|
+
* delayed. The pending probe is bounded (~cpuSampleMs) and never rejects.
|
|
1748
|
+
* - `adaptive`/`strict`: bounded blocking probe (default 300 ms deadline),
|
|
1749
|
+
* then a generation-safe lease applies the effective tool cap for this
|
|
1750
|
+
* run. The caller's `finally` releases it exactly once.
|
|
1751
|
+
*
|
|
1752
|
+
* Never throws: any probe or policy failure leaves this run ungoverned
|
|
1753
|
+
* (§2.1: probe failure must not crash or block the prompt).
|
|
1754
|
+
*/
|
|
1755
|
+
async _beginResourceGovernedRun(promptRunId) {
|
|
1756
|
+
try {
|
|
1757
|
+
const resolved = resolveResourceGovernorSettings(this.settingsManager.getResourceGovernorSettings());
|
|
1758
|
+
if (resolved.mode === "off") {
|
|
1759
|
+
return null;
|
|
1760
|
+
}
|
|
1761
|
+
const resourceObservations = this._openResourceObservations(promptRunId);
|
|
1762
|
+
const probeOptions = {
|
|
1763
|
+
cwd: this._cwd,
|
|
1764
|
+
maxProbeMs: resolved.maxProbeMs,
|
|
1765
|
+
cpuSampleMs: resolved.cpuSampleMs,
|
|
1766
|
+
};
|
|
1767
|
+
// §7.3: Agent.maxToolConcurrency uses undefined for "unlimited"; the
|
|
1768
|
+
// admission contract uses 0 for the same meaning.
|
|
1769
|
+
const configuredCaps = { maxToolConcurrency: this.agent.maxToolConcurrency ?? 0 };
|
|
1770
|
+
if (resolved.mode === "observe") {
|
|
1771
|
+
void captureHostResourceSnapshot(probeOptions)
|
|
1772
|
+
.then((snapshot) => {
|
|
1773
|
+
const decision = decideResourceAdmission({
|
|
1774
|
+
snapshot,
|
|
1775
|
+
config: resolved.admission,
|
|
1776
|
+
configuredCaps,
|
|
1777
|
+
});
|
|
1778
|
+
if (this._latestResourcePromptRunId === promptRunId) {
|
|
1779
|
+
this._lastResourceAdmission = decision;
|
|
1780
|
+
}
|
|
1781
|
+
resourceObservations?.record("resource_snapshot_v1", snapshotObservationFacts(snapshot));
|
|
1782
|
+
resourceObservations?.record("resource_admission_v1", admissionObservationFacts(decision));
|
|
1783
|
+
})
|
|
1784
|
+
.catch(() => { });
|
|
1785
|
+
return null;
|
|
1786
|
+
}
|
|
1787
|
+
const snapshot = await captureHostResourceSnapshot(probeOptions);
|
|
1788
|
+
const decision = decideResourceAdmission({ snapshot, config: resolved.admission, configuredCaps });
|
|
1789
|
+
if (this._latestResourcePromptRunId === promptRunId) {
|
|
1790
|
+
this._lastResourceAdmission = decision;
|
|
1791
|
+
}
|
|
1792
|
+
resourceObservations?.record("resource_snapshot_v1", snapshotObservationFacts(snapshot));
|
|
1793
|
+
resourceObservations?.record("resource_admission_v1", admissionObservationFacts(decision));
|
|
1794
|
+
this._resourceLeaseController ??= new RunResourceLeaseController({
|
|
1795
|
+
getCap: () => this.agent.maxToolConcurrency,
|
|
1796
|
+
setCap: (cap) => {
|
|
1797
|
+
this.agent.maxToolConcurrency = cap;
|
|
1798
|
+
},
|
|
1799
|
+
});
|
|
1800
|
+
const lease = this._resourceLeaseController.acquire({ promptRunId, decision });
|
|
1801
|
+
resourceObservations?.record("resource_lease_acquired_v1", {
|
|
1802
|
+
decisionId: decision.decisionId,
|
|
1803
|
+
appliedToolCap: decision.maxToolConcurrency,
|
|
1804
|
+
});
|
|
1805
|
+
return lease;
|
|
1806
|
+
}
|
|
1807
|
+
catch {
|
|
1808
|
+
return null;
|
|
1809
|
+
}
|
|
1810
|
+
}
|
|
1811
|
+
_openResourceObservations(promptRunId) {
|
|
1812
|
+
this._latestResourcePromptRunId = promptRunId;
|
|
1813
|
+
try {
|
|
1814
|
+
const journal = ResourceObservationJournal.open(this._cwd, promptRunId);
|
|
1815
|
+
this._resourceObservations = journal;
|
|
1816
|
+
this._resourceObservationJournals.set(promptRunId, journal);
|
|
1817
|
+
while (this._resourceObservationJournals.size > MAX_RESOURCE_OBSERVATION_JOURNALS) {
|
|
1818
|
+
const oldestPromptRunId = this._resourceObservationJournals.keys().next().value;
|
|
1819
|
+
if (oldestPromptRunId === undefined)
|
|
1820
|
+
break;
|
|
1821
|
+
this._resourceObservationJournals.delete(oldestPromptRunId);
|
|
1822
|
+
}
|
|
1823
|
+
return journal;
|
|
1824
|
+
}
|
|
1825
|
+
catch {
|
|
1826
|
+
this._resourceObservations = null;
|
|
1827
|
+
this._resourceObservationJournals.delete(promptRunId);
|
|
1828
|
+
return null;
|
|
1829
|
+
}
|
|
1830
|
+
}
|
|
1831
|
+
/** §20.2: record the TUI-side completion sound result in its originating run journal. */
|
|
1832
|
+
recordCompletionSoundResult(promptRunId, result) {
|
|
1833
|
+
const journal = this._resourceObservationJournals.get(promptRunId);
|
|
1834
|
+
journal?.record("completion_sound_result_v1", soundObservationFacts(result));
|
|
1835
|
+
this._resourceObservationJournals.delete(promptRunId);
|
|
1836
|
+
if (this._latestResourcePromptRunId === promptRunId) {
|
|
1837
|
+
this._latestResourcePromptRunId = null;
|
|
1838
|
+
if (this._resourceObservations === journal)
|
|
1839
|
+
this._resourceObservations = null;
|
|
1840
|
+
}
|
|
1841
|
+
}
|
|
1842
|
+
/** §19.4 read-only SDK surface: the most recent resource admission decision, if any. */
|
|
1843
|
+
getCurrentResourceAdmission() {
|
|
1844
|
+
return this._lastResourceAdmission;
|
|
1845
|
+
}
|
|
1846
|
+
/** §19.4 read-only SDK surface: capture a fresh host resource snapshot. */
|
|
1847
|
+
async getHostResourceSnapshot() {
|
|
1848
|
+
const resolved = resolveResourceGovernorSettings(this.settingsManager.getResourceGovernorSettings());
|
|
1849
|
+
return captureHostResourceSnapshot({
|
|
1850
|
+
cwd: this._cwd,
|
|
1851
|
+
maxProbeMs: resolved.maxProbeMs,
|
|
1852
|
+
cpuSampleMs: resolved.cpuSampleMs,
|
|
1853
|
+
});
|
|
1854
|
+
}
|
|
1855
|
+
/** §19.4 read-only SDK surface: shared workload permit pool state, if any. */
|
|
1856
|
+
getWorkloadPermitSnapshot() {
|
|
1857
|
+
return this._workloadPermitPool?.snapshot() ?? null;
|
|
1858
|
+
}
|
|
1859
|
+
/**
|
|
1860
|
+
* §14.1 shared-budget seam: child subagents must reuse this instance
|
|
1861
|
+
* instead of creating a private pool (host oversubscription). The live
|
|
1862
|
+
* child launcher wiring lands in M6.
|
|
1863
|
+
*/
|
|
1864
|
+
get workloadPermitPool() {
|
|
1865
|
+
this._workloadPermitPool ??= new WorkloadPermitPool();
|
|
1866
|
+
return this._workloadPermitPool;
|
|
1867
|
+
}
|
|
1868
|
+
/**
|
|
1869
|
+
* Resource safety gate for the bash boundary (roadmap §9.4/§11, M3).
|
|
1870
|
+
* Runs only in adaptive/strict mode with a recorded admission decision;
|
|
1871
|
+
* observe/off keep v0.96.1 behavior. Never throws: gate machinery
|
|
1872
|
+
* failures leave the command ungated (§2.1), while computed block
|
|
1873
|
+
* verdicts and permit rejections return a bounded §11.3 payload.
|
|
1874
|
+
*/
|
|
1875
|
+
async _acquireBashResourcePermit(command, signal) {
|
|
1876
|
+
try {
|
|
1877
|
+
const resolved = resolveResourceGovernorSettings(this.settingsManager.getResourceGovernorSettings());
|
|
1878
|
+
if (resolved.mode !== "adaptive" && resolved.mode !== "strict") {
|
|
1879
|
+
return {};
|
|
1880
|
+
}
|
|
1881
|
+
const decision = this._lastResourceAdmission;
|
|
1882
|
+
if (decision === null) {
|
|
1883
|
+
return {};
|
|
1884
|
+
}
|
|
1885
|
+
const classification = classifyWorkloadCommand(command);
|
|
1886
|
+
this._resourceObservations?.record("workload_classification_v1", classificationObservationFacts(classification));
|
|
1887
|
+
const verdict = decideResourceSafetyGate({ commandSafety: "allowed", classification, decision });
|
|
1888
|
+
if (verdict.kind === "allow") {
|
|
1889
|
+
return {};
|
|
1890
|
+
}
|
|
1891
|
+
if (verdict.kind === "block") {
|
|
1892
|
+
return { blocked: JSON.stringify(verdict.block) };
|
|
1893
|
+
}
|
|
1894
|
+
this._workloadPermitPool ??= new WorkloadPermitPool({ capacity: decision.maxHeavyProcesses });
|
|
1895
|
+
const pool = this._workloadPermitPool;
|
|
1896
|
+
pool.setCapacity(decision.maxHeavyProcesses);
|
|
1897
|
+
const waitStartedMs = Date.now();
|
|
1898
|
+
this._resourceObservations?.record("workload_permit_wait_v1", {
|
|
1899
|
+
workloadClass: classification.workloadClass,
|
|
1900
|
+
weight: verdict.weight,
|
|
1901
|
+
});
|
|
1902
|
+
try {
|
|
1903
|
+
const permit = await pool.acquire({
|
|
1904
|
+
requestId: `bash-${randomUUID()}`,
|
|
1905
|
+
promptRunId: this._resourceLeaseController?.activeLease?.promptRunId ?? "unleased",
|
|
1906
|
+
workloadClass: classification.workloadClass,
|
|
1907
|
+
weight: verdict.weight,
|
|
1908
|
+
signal,
|
|
1909
|
+
// Bounded §10.3 timeout-aware wait; a settings knob can follow later.
|
|
1910
|
+
timeoutMs: 60_000,
|
|
1911
|
+
});
|
|
1912
|
+
this._resourceObservations?.record("workload_permit_acquired_v1", {
|
|
1913
|
+
workloadClass: classification.workloadClass,
|
|
1914
|
+
weight: verdict.weight,
|
|
1915
|
+
waitMs: Date.now() - waitStartedMs,
|
|
1916
|
+
});
|
|
1917
|
+
return {
|
|
1918
|
+
release: () => {
|
|
1919
|
+
permit.release();
|
|
1920
|
+
this._resourceObservations?.record("workload_permit_released_v1", {
|
|
1921
|
+
workloadClass: classification.workloadClass,
|
|
1922
|
+
weight: verdict.weight,
|
|
1923
|
+
});
|
|
1924
|
+
},
|
|
1925
|
+
};
|
|
1926
|
+
}
|
|
1927
|
+
catch (error) {
|
|
1928
|
+
const code = error instanceof WorkloadPermitError ? error.code : "queue_overflow";
|
|
1929
|
+
return {
|
|
1930
|
+
blocked: JSON.stringify({
|
|
1931
|
+
kind: "resource_pressure",
|
|
1932
|
+
pressure: decision.pressure,
|
|
1933
|
+
action: "defer-heavy",
|
|
1934
|
+
reasonCodes: [...decision.reasons, `resource.permit.${code}`],
|
|
1935
|
+
requiredAction: RESOURCE_PRESSURE_REQUIRED_ACTION,
|
|
1936
|
+
}),
|
|
1937
|
+
};
|
|
1938
|
+
}
|
|
1939
|
+
}
|
|
1940
|
+
catch {
|
|
1941
|
+
return {};
|
|
1664
1942
|
}
|
|
1665
1943
|
}
|
|
1666
1944
|
async _handlePostAgentRun() {
|
|
@@ -1702,8 +1980,13 @@ export class AgentSession {
|
|
|
1702
1980
|
const expandPromptTemplates = options?.expandPromptTemplates ?? true;
|
|
1703
1981
|
const preflightResult = options?.preflightResult;
|
|
1704
1982
|
let currentText = redactSensitiveText(text);
|
|
1705
|
-
|
|
1706
|
-
let
|
|
1983
|
+
const defaultActiveSkills = this._getDefaultActiveSkills();
|
|
1984
|
+
let promptActiveSkillNames = mergePromptActiveSkillNames(defaultActiveSkills, options?.activeSkillNames ?? []);
|
|
1985
|
+
let promptActiveSkillSource = defaultActiveSkills.length > 0
|
|
1986
|
+
? options?.activeSkillSource
|
|
1987
|
+
? `settings+${options.activeSkillSource}`
|
|
1988
|
+
: "settings"
|
|
1989
|
+
: options?.activeSkillSource;
|
|
1707
1990
|
let isBangSkillInvocation = false;
|
|
1708
1991
|
if (expandPromptTemplates) {
|
|
1709
1992
|
const bangInvocation = parseBangInvocation(text, {
|
|
@@ -1715,7 +1998,8 @@ export class AgentSession {
|
|
|
1715
1998
|
? `/skill:${bangInvocation.skillName} ${bangInvocation.prompt}`
|
|
1716
1999
|
: `/skill:${bangInvocation.skillName}`;
|
|
1717
2000
|
promptActiveSkillNames = mergePromptActiveSkillNames(promptActiveSkillNames, bangInvocation.activeSkillNames);
|
|
1718
|
-
promptActiveSkillSource =
|
|
2001
|
+
promptActiveSkillSource =
|
|
2002
|
+
defaultActiveSkills.length > 0 ? `settings+${bangInvocation.source}` : bangInvocation.source;
|
|
1719
2003
|
}
|
|
1720
2004
|
}
|
|
1721
2005
|
let messages;
|
|
@@ -1819,8 +2103,8 @@ export class AgentSession {
|
|
|
1819
2103
|
const turnSystemPromptOptions = {
|
|
1820
2104
|
...this._baseSystemPromptOptions,
|
|
1821
2105
|
contextBudget: this._getContextBudgetOptions(expandedText),
|
|
1822
|
-
|
|
1823
|
-
|
|
2106
|
+
activeSkillNames: promptActiveSkillNames,
|
|
2107
|
+
activeSkillSource: promptActiveSkillSource,
|
|
1824
2108
|
};
|
|
1825
2109
|
const turnSystemPrompt = buildSystemPromptPlan(turnSystemPromptOptions);
|
|
1826
2110
|
// Emit before_agent_start extension event
|