@cognipeer/agent-sdk 0.10.1 → 0.10.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/dist/index.cjs +193 -71
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.mjs +193 -71
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -451,6 +451,13 @@ interface HookMap {
|
|
|
451
451
|
error?: Error;
|
|
452
452
|
durationMs: number;
|
|
453
453
|
executionId: string;
|
|
454
|
+
/**
|
|
455
|
+
* Where `output` came from. `tool` is a real execution (or its error);
|
|
456
|
+
* `hook` is a `preToolUse.result` short-circuit; `cache` is a hit on the
|
|
457
|
+
* tool's own result cache — that value already passed this hook once,
|
|
458
|
+
* when it was stored, so a redactor sees it twice.
|
|
459
|
+
*/
|
|
460
|
+
source?: "tool" | "hook" | "cache";
|
|
454
461
|
};
|
|
455
462
|
output: {
|
|
456
463
|
/** Rewritten output — redaction, normalization, schema coercion. */
|
package/dist/index.d.ts
CHANGED
|
@@ -451,6 +451,13 @@ interface HookMap {
|
|
|
451
451
|
error?: Error;
|
|
452
452
|
durationMs: number;
|
|
453
453
|
executionId: string;
|
|
454
|
+
/**
|
|
455
|
+
* Where `output` came from. `tool` is a real execution (or its error);
|
|
456
|
+
* `hook` is a `preToolUse.result` short-circuit; `cache` is a hit on the
|
|
457
|
+
* tool's own result cache — that value already passed this hook once,
|
|
458
|
+
* when it was stored, so a redactor sees it twice.
|
|
459
|
+
*/
|
|
460
|
+
source?: "tool" | "hook" | "cache";
|
|
454
461
|
};
|
|
455
462
|
output: {
|
|
456
463
|
/** Rewritten output — redaction, normalization, schema coercion. */
|
package/dist/index.mjs
CHANGED
|
@@ -4591,18 +4591,60 @@ function createToolsNode(initialTools, opts) {
|
|
|
4591
4591
|
toolStateRef.__currentToolCallId = toolCallId;
|
|
4592
4592
|
delete toolStateRef.__awaitingApproval;
|
|
4593
4593
|
}
|
|
4594
|
-
|
|
4595
|
-
|
|
4596
|
-
|
|
4597
|
-
|
|
4594
|
+
const stableJson = (value) => {
|
|
4595
|
+
try {
|
|
4596
|
+
if (value === null || typeof value !== "object") return JSON.stringify(value);
|
|
4597
|
+
if (Array.isArray(value)) return `[${value.map(stableJson).join(",")}]`;
|
|
4598
|
+
const keys = Object.keys(value).sort();
|
|
4599
|
+
return `{${keys.map((k) => JSON.stringify(k) + ":" + stableJson(value[k])).join(",")}}`;
|
|
4600
|
+
} catch {
|
|
4601
|
+
return String(value);
|
|
4602
|
+
}
|
|
4603
|
+
};
|
|
4604
|
+
const rejectByPolicy = (gateReason, gatedArgs) => {
|
|
4605
|
+
const reason = gateReason || `Tool call blocked by policy: ${toolName}`;
|
|
4606
|
+
push({ role: "tool", content: reason, tool_call_id: toolCallId, name: tc.name });
|
|
4607
|
+
toolHistory.push({
|
|
4608
|
+
executionId: nanoid(),
|
|
4609
|
+
toolName,
|
|
4610
|
+
args: gatedArgs,
|
|
4611
|
+
output: reason,
|
|
4612
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4613
|
+
tool_call_id: toolCallId,
|
|
4614
|
+
status: "rejected"
|
|
4615
|
+
});
|
|
4616
|
+
onEvent?.({ type: "tool_call", phase: "skipped", name: toolName, id: tc.id, args: gatedArgs, error: { message: reason } });
|
|
4617
|
+
recordTraceEvent(traceSession, {
|
|
4618
|
+
type: "tool_call",
|
|
4619
|
+
label: `Tool Denied - ${toolName}`,
|
|
4620
|
+
actor: { scope: "tool", name: toolName, role: "tool" },
|
|
4621
|
+
status: "skipped",
|
|
4622
|
+
toolDetails,
|
|
4623
|
+
toolExecutionId: toolCallId,
|
|
4624
|
+
sections: buildToolTraceSections({
|
|
4625
|
+
args: gatedArgs,
|
|
4626
|
+
executionId: toolCallId,
|
|
4627
|
+
output: reason,
|
|
4628
|
+
status: "skipped",
|
|
4629
|
+
summary: reason,
|
|
4630
|
+
toolDetails,
|
|
4631
|
+
toolName
|
|
4632
|
+
})
|
|
4633
|
+
});
|
|
4634
|
+
toolCount += 1;
|
|
4635
|
+
return { status: "error" };
|
|
4636
|
+
};
|
|
4637
|
+
const applyPreToolUseGate = async (candidate) => {
|
|
4638
|
+
if (!host?.has("preToolUse")) return { ok: true, args: candidate, ask: false };
|
|
4598
4639
|
const gate = await host.runGate("preToolUse", {
|
|
4599
4640
|
toolName,
|
|
4600
4641
|
toolCallId,
|
|
4601
|
-
args,
|
|
4642
|
+
args: candidate,
|
|
4602
4643
|
tool,
|
|
4603
4644
|
executionCount: countSuccessfulToolExecutions(toolHistory, toolName)
|
|
4604
4645
|
});
|
|
4605
|
-
|
|
4646
|
+
let next = candidate;
|
|
4647
|
+
if (gate.input.args !== candidate) {
|
|
4606
4648
|
const revalidated = validateToolArgs(tool, gate.input.args);
|
|
4607
4649
|
if (!revalidated.ok && resolved.toolResponses.schemaValidation === "strict") {
|
|
4608
4650
|
const message = `Tool argument validation failed after a plugin rewrite for ${toolName}: ${revalidated.message}`;
|
|
@@ -4610,48 +4652,31 @@ function createToolsNode(initialTools, opts) {
|
|
|
4610
4652
|
markToolFailure(message, toolName, toolCallId);
|
|
4611
4653
|
onEvent?.({ type: "tool_call", phase: "error", name: toolName, id: tc.id, args: gate.input.args, error: { message } });
|
|
4612
4654
|
toolCount += 1;
|
|
4613
|
-
return { status: "error" };
|
|
4655
|
+
return { ok: false, outcome: { status: "error" } };
|
|
4614
4656
|
}
|
|
4615
|
-
|
|
4657
|
+
next = revalidated.ok ? revalidated.value : gate.input.args;
|
|
4616
4658
|
}
|
|
4617
4659
|
if (gate.decision === "deny") {
|
|
4618
|
-
|
|
4619
|
-
push({ role: "tool", content: reason, tool_call_id: toolCallId, name: tc.name });
|
|
4620
|
-
toolHistory.push({
|
|
4621
|
-
executionId: nanoid(),
|
|
4622
|
-
toolName,
|
|
4623
|
-
args,
|
|
4624
|
-
output: reason,
|
|
4625
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4626
|
-
tool_call_id: toolCallId,
|
|
4627
|
-
status: "rejected"
|
|
4628
|
-
});
|
|
4629
|
-
onEvent?.({ type: "tool_call", phase: "skipped", name: toolName, id: tc.id, args, error: { message: reason } });
|
|
4630
|
-
recordTraceEvent(traceSession, {
|
|
4631
|
-
type: "tool_call",
|
|
4632
|
-
label: `Tool Denied - ${toolName}`,
|
|
4633
|
-
actor: { scope: "tool", name: toolName, role: "tool" },
|
|
4634
|
-
status: "skipped",
|
|
4635
|
-
toolDetails,
|
|
4636
|
-
toolExecutionId: toolCallId,
|
|
4637
|
-
sections: buildToolTraceSections({
|
|
4638
|
-
args,
|
|
4639
|
-
executionId: toolCallId,
|
|
4640
|
-
output: reason,
|
|
4641
|
-
status: "skipped",
|
|
4642
|
-
summary: reason,
|
|
4643
|
-
toolDetails,
|
|
4644
|
-
toolName
|
|
4645
|
-
})
|
|
4646
|
-
});
|
|
4647
|
-
toolCount += 1;
|
|
4648
|
-
return { status: "error" };
|
|
4649
|
-
}
|
|
4650
|
-
if (gate.decision === "ask") {
|
|
4651
|
-
hookAskedForApproval = true;
|
|
4652
|
-
hookApprovalPrompt = gate.approvalPrompt;
|
|
4660
|
+
return { ok: false, outcome: rejectByPolicy(gate.reason, next) };
|
|
4653
4661
|
}
|
|
4654
|
-
|
|
4662
|
+
return {
|
|
4663
|
+
ok: true,
|
|
4664
|
+
args: next,
|
|
4665
|
+
ask: gate.decision === "ask",
|
|
4666
|
+
approvalPrompt: gate.approvalPrompt,
|
|
4667
|
+
result: gate.shortCircuit
|
|
4668
|
+
};
|
|
4669
|
+
};
|
|
4670
|
+
let hookAskedForApproval = false;
|
|
4671
|
+
let hookApprovalPrompt;
|
|
4672
|
+
let hookResult;
|
|
4673
|
+
{
|
|
4674
|
+
const gated = await applyPreToolUseGate(args);
|
|
4675
|
+
if (!gated.ok) return gated.outcome;
|
|
4676
|
+
args = gated.args;
|
|
4677
|
+
hookAskedForApproval = gated.ask;
|
|
4678
|
+
hookApprovalPrompt = gated.approvalPrompt;
|
|
4679
|
+
if (gated.result !== void 0) hookResult = gated.result;
|
|
4655
4680
|
}
|
|
4656
4681
|
const maxExecutionsPerRun = normalizeMaxExecutionsPerRun(tool.maxExecutionsPerRun);
|
|
4657
4682
|
if (maxExecutionsPerRun !== null) {
|
|
@@ -4736,7 +4761,34 @@ function createToolsNode(initialTools, opts) {
|
|
|
4736
4761
|
return { status: "rejected", approval: approvalEntry };
|
|
4737
4762
|
}
|
|
4738
4763
|
if (approvalEntry.status === "approved" && approvalEntry.approvedArgs !== void 0) {
|
|
4739
|
-
|
|
4764
|
+
const approvedArgs = approvalEntry.approvedArgs;
|
|
4765
|
+
if (stableJson(approvedArgs) !== stableJson(args)) {
|
|
4766
|
+
const settleRefused = (resolution) => {
|
|
4767
|
+
approvalEntry.metadata = { ...approvalEntry.metadata || {}, resolution };
|
|
4768
|
+
approvalEntry.status = "executed";
|
|
4769
|
+
approvalEntry.resolvedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
4770
|
+
pendingByCallId.set(toolCallId, approvalEntry);
|
|
4771
|
+
};
|
|
4772
|
+
const revalidated = validateToolArgs(tool, approvedArgs);
|
|
4773
|
+
if (!revalidated.ok && resolved.toolResponses.schemaValidation === "strict") {
|
|
4774
|
+
const message = `Tool argument validation failed for reviewer-edited arguments of ${toolName}: ${revalidated.message}`;
|
|
4775
|
+
push({ role: "tool", content: message, tool_call_id: toolCallId, name: tc.name });
|
|
4776
|
+
markToolFailure(message, toolName, toolCallId);
|
|
4777
|
+
settleRefused("invalid_args");
|
|
4778
|
+
onEvent?.({ type: "tool_call", phase: "error", name: toolName, id: tc.id, args: approvedArgs, error: { message } });
|
|
4779
|
+
toolCount += 1;
|
|
4780
|
+
return { status: "error", approval: approvalEntry };
|
|
4781
|
+
}
|
|
4782
|
+
const gated = await applyPreToolUseGate(revalidated.ok ? revalidated.value : approvedArgs);
|
|
4783
|
+
if (!gated.ok) {
|
|
4784
|
+
settleRefused("policy_denied");
|
|
4785
|
+
return { ...gated.outcome, approval: approvalEntry };
|
|
4786
|
+
}
|
|
4787
|
+
args = gated.args;
|
|
4788
|
+
if (gated.result !== void 0 && hookResult === void 0) hookResult = gated.result;
|
|
4789
|
+
} else {
|
|
4790
|
+
args = approvedArgs;
|
|
4791
|
+
}
|
|
4740
4792
|
onEvent?.({ type: "tool_approval", status: "approved", id: approvalEntry.id, toolName: approvalEntry.toolName, toolCallId: approvalEntry.toolCallId, decidedBy: approvalEntry.decidedBy, comment: approvalEntry.comment });
|
|
4741
4793
|
}
|
|
4742
4794
|
}
|
|
@@ -4746,16 +4798,6 @@ function createToolsNode(initialTools, opts) {
|
|
|
4746
4798
|
const cacheCfg = tool.cache;
|
|
4747
4799
|
const cacheEnabled = cacheCfg === true || cacheCfg && typeof cacheCfg === "object";
|
|
4748
4800
|
const cacheKeyFn = cacheEnabled && typeof cacheCfg === "object" ? cacheCfg.keyFn : void 0;
|
|
4749
|
-
const stableJson = (value) => {
|
|
4750
|
-
try {
|
|
4751
|
-
if (value === null || typeof value !== "object") return JSON.stringify(value);
|
|
4752
|
-
if (Array.isArray(value)) return `[${value.map(stableJson).join(",")}]`;
|
|
4753
|
-
const keys = Object.keys(value).sort();
|
|
4754
|
-
return `{${keys.map((k) => JSON.stringify(k) + ":" + stableJson(value[k])).join(",")}}`;
|
|
4755
|
-
} catch {
|
|
4756
|
-
return String(value);
|
|
4757
|
-
}
|
|
4758
|
-
};
|
|
4759
4801
|
const cacheKey = cacheEnabled ? `${toolName}|${cacheKeyFn ? cacheKeyFn(args) : stableJson(args)}` : void 0;
|
|
4760
4802
|
const toolCache = state.toolCache = state.toolCache || {};
|
|
4761
4803
|
let cachedHit = void 0;
|
|
@@ -4803,6 +4845,22 @@ function createToolsNode(initialTools, opts) {
|
|
|
4803
4845
|
try {
|
|
4804
4846
|
if (cachedHit !== void 0) {
|
|
4805
4847
|
const executionId2 = nanoid();
|
|
4848
|
+
if (host?.has("postToolUse")) {
|
|
4849
|
+
const shortGate = await host.runGate("postToolUse", {
|
|
4850
|
+
toolName,
|
|
4851
|
+
toolCallId,
|
|
4852
|
+
args,
|
|
4853
|
+
output: cachedHit,
|
|
4854
|
+
durationMs: 0,
|
|
4855
|
+
executionId: executionId2,
|
|
4856
|
+
source: shortCircuitSource === "plugin" ? "hook" : "cache"
|
|
4857
|
+
});
|
|
4858
|
+
if (shortGate.decision === "deny") {
|
|
4859
|
+
cachedHit = shortGate.reason || `Tool output withheld by policy: ${toolName}`;
|
|
4860
|
+
} else if (shortGate.input.output !== cachedHit) {
|
|
4861
|
+
cachedHit = shortGate.input.output;
|
|
4862
|
+
}
|
|
4863
|
+
}
|
|
4806
4864
|
const { output: compressedCachedHit, stats: cachedContextPilotStats } = maybeCompressToolOutput(toolName, cachedHit, executionId2);
|
|
4807
4865
|
const responsePolicy2 = applyToolResponseHardCap(toolName, compressedCachedHit, executionId2, resolved);
|
|
4808
4866
|
toolHistory.push({
|
|
@@ -4969,7 +5027,8 @@ function createToolsNode(initialTools, opts) {
|
|
|
4969
5027
|
args,
|
|
4970
5028
|
output,
|
|
4971
5029
|
durationMs,
|
|
4972
|
-
executionId
|
|
5030
|
+
executionId,
|
|
5031
|
+
source: "tool"
|
|
4973
5032
|
});
|
|
4974
5033
|
if (postGate.decision === "deny") {
|
|
4975
5034
|
output = postGate.reason || `Tool output withheld by policy: ${toolName}`;
|
|
@@ -5064,7 +5123,8 @@ function createToolsNode(initialTools, opts) {
|
|
|
5064
5123
|
output: message,
|
|
5065
5124
|
error: error instanceof Error ? error : new Error(message),
|
|
5066
5125
|
durationMs,
|
|
5067
|
-
executionId
|
|
5126
|
+
executionId,
|
|
5127
|
+
source: "tool"
|
|
5068
5128
|
});
|
|
5069
5129
|
if (errorGate.decision === "deny") {
|
|
5070
5130
|
message = errorGate.reason || `Tool error withheld by policy: ${toolName}`;
|
|
@@ -5740,7 +5800,14 @@ var DISALLOWED_CTX_KEYS = /* @__PURE__ */ new Set([
|
|
|
5740
5800
|
// Session bookkeeping: a resumed run must open its OWN session, so these
|
|
5741
5801
|
// must not travel in a snapshot.
|
|
5742
5802
|
"__pluginRunStarted",
|
|
5743
|
-
"__pluginRunEnded"
|
|
5803
|
+
"__pluginRunEnded",
|
|
5804
|
+
// Set by restoreSnapshot on the way OUT, consumed by the next invoke. Never
|
|
5805
|
+
// persisted: a snapshot of a restored run would otherwise mark every later
|
|
5806
|
+
// restore as "resumed" forever.
|
|
5807
|
+
"__restoredFromSnapshot",
|
|
5808
|
+
// A per-turn verdict. It describes the run that produced the snapshot, not
|
|
5809
|
+
// the run that will resume from it.
|
|
5810
|
+
"__guardrailBlocked"
|
|
5744
5811
|
]);
|
|
5745
5812
|
var clone = (value) => {
|
|
5746
5813
|
if (typeof globalThis.structuredClone === "function") {
|
|
@@ -6364,6 +6431,7 @@ var SLOT_NAMES = [
|
|
|
6364
6431
|
"contextBuilder"
|
|
6365
6432
|
];
|
|
6366
6433
|
var DECISION_RANK = { allow: 0, ask: 1, deny: 2 };
|
|
6434
|
+
var isHookDecision = (value) => typeof value === "string" && Object.prototype.hasOwnProperty.call(DECISION_RANK, value);
|
|
6367
6435
|
function escalate(current, next) {
|
|
6368
6436
|
return DECISION_RANK[next] > DECISION_RANK[current] ? next : current;
|
|
6369
6437
|
}
|
|
@@ -6373,6 +6441,15 @@ var HookTimeoutError = class extends Error {
|
|
|
6373
6441
|
this.name = "HookTimeoutError";
|
|
6374
6442
|
}
|
|
6375
6443
|
};
|
|
6444
|
+
var InvalidHookDecisionError = class extends Error {
|
|
6445
|
+
constructor(plugin, hook, value) {
|
|
6446
|
+
const shown = typeof value === "string" ? JSON.stringify(value) : String(value);
|
|
6447
|
+
super(
|
|
6448
|
+
`plugin "${plugin}" hook "${hook}" returned an unknown decision ${shown}; expected "allow", "ask" or "deny"`
|
|
6449
|
+
);
|
|
6450
|
+
this.name = "InvalidHookDecisionError";
|
|
6451
|
+
}
|
|
6452
|
+
};
|
|
6376
6453
|
function withTimeout(value, ms, label) {
|
|
6377
6454
|
if (!ms || !Number.isFinite(ms) || ms <= 0) return Promise.resolve(value);
|
|
6378
6455
|
return new Promise((resolve, reject) => {
|
|
@@ -6662,10 +6739,18 @@ function createPluginHost(plugins = [], options = {}) {
|
|
|
6662
6739
|
`plugin "${entry.plugin}" hook "${hook}"`
|
|
6663
6740
|
);
|
|
6664
6741
|
output = raw ?? void 0;
|
|
6742
|
+
if (output && typeof output === "object" && output.decision !== void 0 && !isHookDecision(output.decision)) {
|
|
6743
|
+
throw new InvalidHookDecisionError(entry.plugin, hook, output.decision);
|
|
6744
|
+
}
|
|
6665
6745
|
} catch (err) {
|
|
6666
6746
|
const message = err instanceof Error ? err.message : String(err);
|
|
6667
6747
|
const timedOut = err instanceof HookTimeoutError;
|
|
6668
|
-
|
|
6748
|
+
const badDecision = err instanceof InvalidHookDecisionError;
|
|
6749
|
+
if (badDecision) {
|
|
6750
|
+
logger.error(`plugin "${entry.plugin}" hook "${hook}" returned an invalid decision:`, message);
|
|
6751
|
+
} else {
|
|
6752
|
+
logger.warn(`plugin "${entry.plugin}" hook "${hook}" failed:`, message);
|
|
6753
|
+
}
|
|
6669
6754
|
emitPluginEvent(entry, hook, {
|
|
6670
6755
|
phase: timedOut ? "timeout" : "error",
|
|
6671
6756
|
error: { message },
|
|
@@ -6677,8 +6762,9 @@ function createPluginHost(plugins = [], options = {}) {
|
|
|
6677
6762
|
durationMs: performanceNow() - startedAt
|
|
6678
6763
|
});
|
|
6679
6764
|
if (entry.failureMode === "closed") {
|
|
6765
|
+
const cause = timedOut ? "timed out" : badDecision ? "invalid decision" : "hook error";
|
|
6680
6766
|
result.decision = "deny";
|
|
6681
|
-
result.reason = `${entry.plugin}: ${
|
|
6767
|
+
result.reason = `${entry.plugin}: ${cause} (fail-closed) \u2014 ${message}`;
|
|
6682
6768
|
result.deniedBy = entry.plugin;
|
|
6683
6769
|
result.input = current;
|
|
6684
6770
|
return result;
|
|
@@ -6736,11 +6822,19 @@ function createPluginHost(plugins = [], options = {}) {
|
|
|
6736
6822
|
if (output.metadata && typeof output.metadata === "object") {
|
|
6737
6823
|
result.metadata = { ...result.metadata ?? {}, ...output.metadata };
|
|
6738
6824
|
}
|
|
6739
|
-
|
|
6825
|
+
let decision = output.decision;
|
|
6826
|
+
if (decision === "ask" && hook !== "preToolUse") {
|
|
6827
|
+
logger.warn(
|
|
6828
|
+
`plugin "${entry.plugin}" returned "ask" from "${hook}", which cannot pause for approval; treating it as "deny".`
|
|
6829
|
+
);
|
|
6830
|
+
decision = "deny";
|
|
6831
|
+
}
|
|
6740
6832
|
const escalated = decision ? escalate(result.decision, decision) : result.decision;
|
|
6741
6833
|
const escalatesHere = escalated !== result.decision;
|
|
6742
6834
|
result.decision = escalated;
|
|
6743
|
-
if (
|
|
6835
|
+
if (escalatesHere) {
|
|
6836
|
+
result.reason = typeof output.reason === "string" ? `${entry.plugin}: ${output.reason}` : void 0;
|
|
6837
|
+
} else if (typeof output.reason === "string" && !result.reason) {
|
|
6744
6838
|
result.reason = `${entry.plugin}: ${output.reason}`;
|
|
6745
6839
|
}
|
|
6746
6840
|
if (mutatedHere) {
|
|
@@ -6834,7 +6928,7 @@ async function openPluginSession(runHost, params) {
|
|
|
6834
6928
|
const appended = startGate.collected.systemPromptAppend ?? [];
|
|
6835
6929
|
const systemPromptAppend = appended.length > 0 ? appended.join("\n\n") : void 0;
|
|
6836
6930
|
const last = messages[messages.length - 1];
|
|
6837
|
-
if (params.
|
|
6931
|
+
if (params.pausedMidRun || last?.role !== "user" || !runHost.has("userPromptSubmit")) {
|
|
6838
6932
|
return { messages, systemPromptAppend };
|
|
6839
6933
|
}
|
|
6840
6934
|
const content = last.content;
|
|
@@ -7079,6 +7173,11 @@ function createAgent(opts) {
|
|
|
7079
7173
|
delete nextCtx.__paused;
|
|
7080
7174
|
state = { ...state, ctx: Object.keys(nextCtx).length > 0 ? nextCtx : void 0 };
|
|
7081
7175
|
}
|
|
7176
|
+
if (state.ctx?.__restoredFromSnapshot) {
|
|
7177
|
+
const nextCtx = { ...state.ctx };
|
|
7178
|
+
delete nextCtx.__restoredFromSnapshot;
|
|
7179
|
+
state = { ...state, ctx: Object.keys(nextCtx).length > 0 ? nextCtx : void 0 };
|
|
7180
|
+
}
|
|
7082
7181
|
let resumeStage = null;
|
|
7083
7182
|
if (state.ctx?.__resumeStage) {
|
|
7084
7183
|
const nextCtx = { ...state.ctx };
|
|
@@ -7353,7 +7452,7 @@ function createAgent(opts) {
|
|
|
7353
7452
|
continue;
|
|
7354
7453
|
}
|
|
7355
7454
|
if (toolCalls.length === 0) {
|
|
7356
|
-
if (soManager && !state.ctx?.__finalizedDueToStructuredOutput && !state.ctx?.__structuredOutputForceFinalize) {
|
|
7455
|
+
if (soManager && !state.ctx?.__finalizedDueToStructuredOutput && !state.ctx?.__structuredOutputForceFinalize && !state.ctx?.__guardrailBlocked) {
|
|
7357
7456
|
if (soManager.strategy.kind === "native") {
|
|
7358
7457
|
const assistantText = extractMessageText2(lastMsg);
|
|
7359
7458
|
if (assistantText) {
|
|
@@ -7522,6 +7621,7 @@ function createAgent(opts) {
|
|
|
7522
7621
|
delete ctx.__plugins;
|
|
7523
7622
|
delete ctx.__applySystemPromptContribution;
|
|
7524
7623
|
delete ctx.__pluginState;
|
|
7624
|
+
delete ctx.__guardrailBlocked;
|
|
7525
7625
|
const inheritedSession = config?.__pluginSession;
|
|
7526
7626
|
ctx.__runId = inheritedSession?.runId ?? traceSession?.sessionId ?? `run_${nanoid(10)}`;
|
|
7527
7627
|
const stateHolder = inheritedSession?.stateHolder ?? { value: void 0 };
|
|
@@ -7571,9 +7671,11 @@ function createAgent(opts) {
|
|
|
7571
7671
|
usage: input.usage || { perRequest: [], totals: {} }
|
|
7572
7672
|
};
|
|
7573
7673
|
stateHolder.value = initial;
|
|
7574
|
-
const
|
|
7575
|
-
input.ctx?.
|
|
7674
|
+
const pausedMidRun = Boolean(
|
|
7675
|
+
input.ctx?.__paused || input.ctx?.__resumeStage || input.ctx?.__awaitingApproval || input.ctx?.__awaitingUserQuestion
|
|
7576
7676
|
);
|
|
7677
|
+
const resumed = Boolean(input.ctx?.__restoredFromSnapshot || pausedMidRun);
|
|
7678
|
+
delete ctx.__restoredFromSnapshot;
|
|
7577
7679
|
const startedAt = Date.now();
|
|
7578
7680
|
let sessionEnded = false;
|
|
7579
7681
|
const endSession = async (status, payload) => {
|
|
@@ -7599,6 +7701,7 @@ function createAgent(opts) {
|
|
|
7599
7701
|
const opened = await openPluginSession(runHost, {
|
|
7600
7702
|
messages: initial.messages,
|
|
7601
7703
|
resumed,
|
|
7704
|
+
pausedMidRun,
|
|
7602
7705
|
config
|
|
7603
7706
|
});
|
|
7604
7707
|
if (opened.messages !== initial.messages) {
|
|
@@ -10255,6 +10358,11 @@ ${pluginAppend}`;
|
|
|
10255
10358
|
const instance = {
|
|
10256
10359
|
invoke: async (input, config) => {
|
|
10257
10360
|
await ensurePluginSetup();
|
|
10361
|
+
if (input?.ctx?.__guardrailBlocked !== void 0) {
|
|
10362
|
+
const clearedCtx = { ...input.ctx };
|
|
10363
|
+
delete clearedCtx.__guardrailBlocked;
|
|
10364
|
+
input = { ...input, ctx: clearedCtx };
|
|
10365
|
+
}
|
|
10258
10366
|
const sessionHolder = { value: input };
|
|
10259
10367
|
const emitSessionEvent = (event) => {
|
|
10260
10368
|
try {
|
|
@@ -10305,12 +10413,20 @@ ${pluginAppend}`;
|
|
|
10305
10413
|
stateHolder: sessionHolder
|
|
10306
10414
|
}
|
|
10307
10415
|
};
|
|
10308
|
-
const
|
|
10309
|
-
input.ctx?.
|
|
10416
|
+
const pausedMidRun = Boolean(
|
|
10417
|
+
input.ctx?.__paused || input.ctx?.__resumeStage || input.ctx?.__awaitingApproval || input.ctx?.__awaitingUserQuestion
|
|
10310
10418
|
);
|
|
10419
|
+
const resumed = Boolean(input.ctx?.__restoredFromSnapshot || pausedMidRun);
|
|
10420
|
+
if (input.ctx?.__restoredFromSnapshot) {
|
|
10421
|
+
const consumedCtx = { ...input.ctx };
|
|
10422
|
+
delete consumedCtx.__restoredFromSnapshot;
|
|
10423
|
+
input = { ...input, ctx: consumedCtx };
|
|
10424
|
+
sessionHolder.value = input;
|
|
10425
|
+
}
|
|
10311
10426
|
const opened = await openPluginSession(runHost, {
|
|
10312
10427
|
messages: input.messages || [],
|
|
10313
10428
|
resumed,
|
|
10429
|
+
pausedMidRun,
|
|
10314
10430
|
config
|
|
10315
10431
|
});
|
|
10316
10432
|
if (opened.denied) {
|
|
@@ -11100,7 +11216,7 @@ var HOOKS = {
|
|
|
11100
11216
|
sessionStart: { implemented: true },
|
|
11101
11217
|
userPromptSubmit: {
|
|
11102
11218
|
implemented: true,
|
|
11103
|
-
notes: "Fires once per run
|
|
11219
|
+
notes: "Fires once per run whenever the transcript tail is a NEW user turn \u2014 including a turn appended to a state that was restored from a snapshot. Skipped on a genuine resume, where the tail is a tool result rather than a user message."
|
|
11104
11220
|
},
|
|
11105
11221
|
preModelCall: {
|
|
11106
11222
|
implemented: true,
|
|
@@ -11113,7 +11229,7 @@ var HOOKS = {
|
|
|
11113
11229
|
},
|
|
11114
11230
|
postToolUse: {
|
|
11115
11231
|
implemented: true,
|
|
11116
|
-
notes: "Raw output, before compression and the hard cap. Also fires on a tool ERROR. Does NOT fire for a call that parks the run."
|
|
11232
|
+
notes: "Raw output, before compression and the hard cap. Also fires on a tool ERROR, on a preToolUse `result` short-circuit and on a tool-cache hit (`input.source` says which). Does NOT fire for a call that parks the run."
|
|
11117
11233
|
},
|
|
11118
11234
|
preCompact: { implemented: true },
|
|
11119
11235
|
postCompact: { implemented: true },
|
|
@@ -12097,6 +12213,12 @@ function auditLog(config = {}) {
|
|
|
12097
12213
|
return "[unserializable]";
|
|
12098
12214
|
}
|
|
12099
12215
|
};
|
|
12216
|
+
const renderDetail = (detail) => {
|
|
12217
|
+
if (!detail || typeof detail !== "object" || Array.isArray(detail) || !("args" in detail)) return detail;
|
|
12218
|
+
const { args, ...rest } = detail;
|
|
12219
|
+
const rendered = renderArgs(args);
|
|
12220
|
+
return rendered === void 0 ? rest : { ...rest, args: rendered };
|
|
12221
|
+
};
|
|
12100
12222
|
return {
|
|
12101
12223
|
name: config.name ?? "audit-log",
|
|
12102
12224
|
// Lowest number: runs first, so denials by later plugins are still recorded
|
|
@@ -12125,7 +12247,7 @@ function auditLog(config = {}) {
|
|
|
12125
12247
|
at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
12126
12248
|
kind: "notification",
|
|
12127
12249
|
status: kind,
|
|
12128
|
-
detail
|
|
12250
|
+
detail: renderDetail(detail)
|
|
12129
12251
|
});
|
|
12130
12252
|
},
|
|
12131
12253
|
sessionEnd: async ({ status }, ctx) => {
|