@dudousxd/nestjs-agent-core 0.19.0 → 0.20.0
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/README.md +2 -1
- package/dist/guardrails/index.d.cts +1 -1
- package/dist/guardrails/index.d.ts +1 -1
- package/dist/index.cjs +283 -29
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +144 -5
- package/dist/index.d.ts +144 -5
- package/dist/index.js +277 -29
- package/dist/index.js.map +1 -1
- package/dist/{tool-Q2rmGeaG.d.cts → tool-B2Dq9ZwF.d.cts} +82 -2
- package/dist/{tool-Q2rmGeaG.d.ts → tool-B2Dq9ZwF.d.ts} +82 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -215,6 +215,63 @@ function truncateDetailContent(content) {
|
|
|
215
215
|
}
|
|
216
216
|
__name(truncateDetailContent, "truncateDetailContent");
|
|
217
217
|
|
|
218
|
+
// src/spi/approval-policy.ts
|
|
219
|
+
var REQUESTER_APPROVER = "requester";
|
|
220
|
+
var DefaultApprovalPolicy = class {
|
|
221
|
+
static {
|
|
222
|
+
__name(this, "DefaultApprovalPolicy");
|
|
223
|
+
}
|
|
224
|
+
requirementFor(tool) {
|
|
225
|
+
return {
|
|
226
|
+
required: tool.kind === "action",
|
|
227
|
+
approver: REQUESTER_APPROVER
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
function defaultCanDecide(actor, decision) {
|
|
232
|
+
if (decision.approver === REQUESTER_APPROVER) {
|
|
233
|
+
return actor.id === decision.requesterRef;
|
|
234
|
+
}
|
|
235
|
+
return actor.roles?.includes(decision.approver) === true;
|
|
236
|
+
}
|
|
237
|
+
__name(defaultCanDecide, "defaultCanDecide");
|
|
238
|
+
async function mayDecideApproval(policy, actor, decision) {
|
|
239
|
+
if (policy?.canDecide !== void 0) {
|
|
240
|
+
return policy.canDecide(actor, decision);
|
|
241
|
+
}
|
|
242
|
+
return defaultCanDecide(actor, decision);
|
|
243
|
+
}
|
|
244
|
+
__name(mayDecideApproval, "mayDecideApproval");
|
|
245
|
+
function toolCallApprovalFromRow(row) {
|
|
246
|
+
if (row.approver === null || row.approver === void 0) {
|
|
247
|
+
return null;
|
|
248
|
+
}
|
|
249
|
+
const status = row.status === "pending_approval" ? "pending" : row.status === "rejected" ? "rejected" : row.status === "expired" ? "expired" : "approved";
|
|
250
|
+
const expiresAt = row.expiresAt instanceof Date ? row.expiresAt.toISOString() : typeof row.expiresAt === "string" ? row.expiresAt : void 0;
|
|
251
|
+
const decided = status === "approved" || status === "rejected";
|
|
252
|
+
return {
|
|
253
|
+
toolCallId: row.toolCallId,
|
|
254
|
+
approver: row.approver,
|
|
255
|
+
status,
|
|
256
|
+
...expiresAt !== void 0 ? {
|
|
257
|
+
expiresAt
|
|
258
|
+
} : {},
|
|
259
|
+
...row.remember === true ? {
|
|
260
|
+
remember: true
|
|
261
|
+
} : {},
|
|
262
|
+
...decided && typeof row.executedByRef === "string" ? {
|
|
263
|
+
decidedBy: row.executedByRef
|
|
264
|
+
} : {},
|
|
265
|
+
...decided && typeof row.decidedVia === "string" ? {
|
|
266
|
+
decidedVia: row.decidedVia
|
|
267
|
+
} : {},
|
|
268
|
+
...status === "rejected" && typeof row.error === "string" ? {
|
|
269
|
+
reason: row.error
|
|
270
|
+
} : {}
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
__name(toolCallApprovalFromRow, "toolCallApprovalFromRow");
|
|
274
|
+
|
|
218
275
|
// src/governance/compute.ts
|
|
219
276
|
function estimateCost(usage, price) {
|
|
220
277
|
if (price === void 0) {
|
|
@@ -2765,15 +2822,33 @@ async function claimToolCall(turn, call) {
|
|
|
2765
2822
|
const spec = deps.registry.spec(call.name);
|
|
2766
2823
|
const kind = call.kind ?? declaredKind(deps, call.name);
|
|
2767
2824
|
const awaitsHuman = kind === "action" || kind === "ask";
|
|
2825
|
+
const approval = kind === "action" ? await claimApproval(turn, call, spec) : void 0;
|
|
2826
|
+
const parks = kind === "ask" || approval?.mode === "ask";
|
|
2768
2827
|
await deps.store.recordToolCall({
|
|
2769
2828
|
toolCallId: call.id,
|
|
2770
2829
|
messageId,
|
|
2771
2830
|
toolName: call.name,
|
|
2772
2831
|
toolType: awaitsHuman ? "action" : "read",
|
|
2773
2832
|
input: call.input,
|
|
2774
|
-
status:
|
|
2775
|
-
runId: hooks.runId
|
|
2833
|
+
status: parks ? "pending_approval" : "auto_executed",
|
|
2834
|
+
runId: hooks.runId,
|
|
2835
|
+
...approval !== void 0 && approval.mode !== "auto" ? {
|
|
2836
|
+
approver: approval.approver
|
|
2837
|
+
} : {},
|
|
2838
|
+
...approval?.mode === "ask" && approval.expiresAt !== void 0 ? {
|
|
2839
|
+
expiresAt: approval.expiresAt
|
|
2840
|
+
} : {}
|
|
2776
2841
|
});
|
|
2842
|
+
if (approval?.mode === "ask") {
|
|
2843
|
+
await turn.writer.write(encodeStreamEvent({
|
|
2844
|
+
kind: "approval-requested",
|
|
2845
|
+
id: call.id,
|
|
2846
|
+
approver: approval.approver,
|
|
2847
|
+
...approval.expiresAt !== void 0 ? {
|
|
2848
|
+
expiresAt: approval.expiresAt
|
|
2849
|
+
} : {}
|
|
2850
|
+
}));
|
|
2851
|
+
}
|
|
2777
2852
|
return {
|
|
2778
2853
|
kind,
|
|
2779
2854
|
...spec?.targetAgent !== void 0 ? {
|
|
@@ -2783,6 +2858,9 @@ async function claimToolCall(turn, call) {
|
|
|
2783
2858
|
// deployment with no detached edge writes the same bytes here it always has.
|
|
2784
2859
|
...spec?.detached === true ? {
|
|
2785
2860
|
detached: true
|
|
2861
|
+
} : {},
|
|
2862
|
+
...approval !== void 0 ? {
|
|
2863
|
+
approval
|
|
2786
2864
|
} : {}
|
|
2787
2865
|
};
|
|
2788
2866
|
});
|
|
@@ -2802,10 +2880,52 @@ async function claimToolCall(turn, call) {
|
|
|
2802
2880
|
...persisted?.detached === true ? {
|
|
2803
2881
|
detached: true
|
|
2804
2882
|
} : {},
|
|
2883
|
+
...toolType === "action" && persisted?.approval !== void 0 ? {
|
|
2884
|
+
approval: persisted.approval
|
|
2885
|
+
} : {},
|
|
2805
2886
|
ctx: toolContext(deps, input, hooks)
|
|
2806
2887
|
};
|
|
2807
2888
|
}
|
|
2808
2889
|
__name(claimToolCall, "claimToolCall");
|
|
2890
|
+
async function claimApproval(turn, call, spec) {
|
|
2891
|
+
const { deps, input, hooks } = turn;
|
|
2892
|
+
const policy = deps.approvalPolicy ?? new DefaultApprovalPolicy();
|
|
2893
|
+
const requirement = await policy.requirementFor({
|
|
2894
|
+
name: call.name,
|
|
2895
|
+
kind: "action",
|
|
2896
|
+
...spec !== void 0 ? {
|
|
2897
|
+
spec
|
|
2898
|
+
} : {}
|
|
2899
|
+
}, input.actor, {
|
|
2900
|
+
threadId: input.threadId,
|
|
2901
|
+
runId: hooks.runId,
|
|
2902
|
+
...input.agentName !== void 0 ? {
|
|
2903
|
+
agentName: input.agentName
|
|
2904
|
+
} : {}
|
|
2905
|
+
});
|
|
2906
|
+
if (!requirement.required) {
|
|
2907
|
+
return {
|
|
2908
|
+
mode: "auto"
|
|
2909
|
+
};
|
|
2910
|
+
}
|
|
2911
|
+
const remembered = await deps.store.rememberedApprovals?.(input.threadId) ?? [];
|
|
2912
|
+
if (remembered.includes(call.name)) {
|
|
2913
|
+
return {
|
|
2914
|
+
mode: "remembered",
|
|
2915
|
+
approver: requirement.approver
|
|
2916
|
+
};
|
|
2917
|
+
}
|
|
2918
|
+
const ttlMs = requirement.ttlMs !== void 0 && Number.isFinite(requirement.ttlMs) && requirement.ttlMs > 0 ? Math.floor(requirement.ttlMs) : void 0;
|
|
2919
|
+
return {
|
|
2920
|
+
mode: "ask",
|
|
2921
|
+
approver: requirement.approver,
|
|
2922
|
+
...ttlMs !== void 0 ? {
|
|
2923
|
+
ttlMs,
|
|
2924
|
+
expiresAt: new Date(Date.now() + ttlMs).toISOString()
|
|
2925
|
+
} : {}
|
|
2926
|
+
};
|
|
2927
|
+
}
|
|
2928
|
+
__name(claimApproval, "claimApproval");
|
|
2809
2929
|
async function loadSkillIntoTurn(turn, claimed, startedAt) {
|
|
2810
2930
|
const { deps, input, hooks } = turn;
|
|
2811
2931
|
const { call } = claimed;
|
|
@@ -2989,17 +3109,50 @@ async function invokeClaimedTool(turn, claimed) {
|
|
|
2989
3109
|
}
|
|
2990
3110
|
}
|
|
2991
3111
|
__name(invokeClaimedTool, "invokeClaimedTool");
|
|
2992
|
-
async function recordToolOutcome(turn, claimed, outcome, deciderRef) {
|
|
3112
|
+
async function recordToolOutcome(turn, claimed, outcome, deciderRef, meta) {
|
|
2993
3113
|
const { deps, hooks } = turn;
|
|
2994
3114
|
const { call } = claimed;
|
|
2995
3115
|
const toolType = claimed.toolType === "action" ? "action" : "read";
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3116
|
+
const decided = meta === void 0 ? {} : {
|
|
3117
|
+
executedByRef: meta.decidedBy,
|
|
3118
|
+
...meta.decidedVia !== void 0 ? {
|
|
3119
|
+
decidedVia: meta.decidedVia
|
|
3120
|
+
} : {},
|
|
3121
|
+
...meta.remember === true ? {
|
|
3122
|
+
remember: true
|
|
3123
|
+
} : {}
|
|
3124
|
+
};
|
|
3125
|
+
const settle = /* @__PURE__ */ __name(async () => {
|
|
3126
|
+
if (meta === void 0 || !meta.streamed) {
|
|
3127
|
+
return;
|
|
3128
|
+
}
|
|
3129
|
+
await turn.writer.write(encodeStreamEvent({
|
|
3130
|
+
kind: "approval-settled",
|
|
3131
|
+
id: call.id,
|
|
3132
|
+
status: "approved",
|
|
3133
|
+
...meta.approver !== void 0 ? {
|
|
3134
|
+
approver: meta.approver
|
|
3135
|
+
} : {},
|
|
3136
|
+
decidedBy: meta.decidedBy,
|
|
3137
|
+
...meta.decidedVia !== void 0 ? {
|
|
3138
|
+
decidedVia: meta.decidedVia
|
|
3139
|
+
} : {},
|
|
3140
|
+
...meta.remember === true ? {
|
|
3141
|
+
remember: true
|
|
3142
|
+
} : {}
|
|
3002
3143
|
}));
|
|
3144
|
+
}, "settle");
|
|
3145
|
+
if (outcome.status === "failed") {
|
|
3146
|
+
await hooks.step(`persist:toolfail:${call.id}`, async () => {
|
|
3147
|
+
await deps.store.updateToolCall({
|
|
3148
|
+
toolCallId: call.id,
|
|
3149
|
+
status: "failed",
|
|
3150
|
+
error: outcome.error,
|
|
3151
|
+
executionMs: outcome.executionMs,
|
|
3152
|
+
...decided
|
|
3153
|
+
});
|
|
3154
|
+
await settle();
|
|
3155
|
+
});
|
|
3003
3156
|
publishAgentToolCall({
|
|
3004
3157
|
runId: hooks.runId,
|
|
3005
3158
|
toolName: call.name,
|
|
@@ -3014,15 +3167,19 @@ async function recordToolOutcome(turn, claimed, outcome, deciderRef) {
|
|
|
3014
3167
|
error: outcome.error
|
|
3015
3168
|
};
|
|
3016
3169
|
}
|
|
3017
|
-
await hooks.step(`persist:toolexec:${call.id}`, () =>
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
3170
|
+
await hooks.step(`persist:toolexec:${call.id}`, async () => {
|
|
3171
|
+
await deps.store.updateToolCall({
|
|
3172
|
+
toolCallId: call.id,
|
|
3173
|
+
status: "executed",
|
|
3174
|
+
output: outcome.output,
|
|
3175
|
+
executionMs: outcome.executionMs,
|
|
3176
|
+
...toolType === "action" ? {
|
|
3177
|
+
executedByRef: deciderRef
|
|
3178
|
+
} : {},
|
|
3179
|
+
...decided
|
|
3180
|
+
});
|
|
3181
|
+
await settle();
|
|
3182
|
+
});
|
|
3026
3183
|
publishAgentToolCall({
|
|
3027
3184
|
runId: hooks.runId,
|
|
3028
3185
|
toolName: call.name,
|
|
@@ -3160,18 +3317,53 @@ async function runClaimedToolCall(turn, claimed) {
|
|
|
3160
3317
|
return elicitToolCall(turn, claimed);
|
|
3161
3318
|
}
|
|
3162
3319
|
let deciderRef = input.actor.id;
|
|
3163
|
-
|
|
3164
|
-
|
|
3320
|
+
let meta;
|
|
3321
|
+
if (toolType === "action" && claimed.approval?.mode === "remembered") {
|
|
3322
|
+
meta = {
|
|
3323
|
+
approver: claimed.approval.approver,
|
|
3324
|
+
decidedBy: input.actor.id,
|
|
3325
|
+
decidedVia: "remembered",
|
|
3326
|
+
remember: true,
|
|
3327
|
+
streamed: true
|
|
3328
|
+
};
|
|
3329
|
+
} else if (toolType === "action" && claimed.approval?.mode !== "auto") {
|
|
3330
|
+
const ttlMs = claimed.approval?.mode === "ask" ? claimed.approval.ttlMs : void 0;
|
|
3331
|
+
const decision = ttlMs !== void 0 ? await hooks.awaitApproval(call, ctx, {
|
|
3332
|
+
timeoutMs: ttlMs
|
|
3333
|
+
}) : await hooks.awaitApproval(call, ctx);
|
|
3165
3334
|
deciderRef = decision.executedByRef ?? input.actor.id;
|
|
3335
|
+
const streamsSettlement = claimed.approval !== void 0;
|
|
3336
|
+
if (decision.expired === true) {
|
|
3337
|
+
return expireToolCall(turn, claimed);
|
|
3338
|
+
}
|
|
3166
3339
|
if (!decision.approved) {
|
|
3167
|
-
await hooks.step(`persist:toolreject:${call.id}`, () =>
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
|
|
3174
|
-
|
|
3340
|
+
await hooks.step(`persist:toolreject:${call.id}`, async () => {
|
|
3341
|
+
await deps.store.updateToolCall({
|
|
3342
|
+
toolCallId: call.id,
|
|
3343
|
+
status: "rejected",
|
|
3344
|
+
executedByRef: deciderRef,
|
|
3345
|
+
...decision.reason !== void 0 ? {
|
|
3346
|
+
error: decision.reason
|
|
3347
|
+
} : {},
|
|
3348
|
+
...decision.decidedVia !== void 0 ? {
|
|
3349
|
+
decidedVia: decision.decidedVia
|
|
3350
|
+
} : {}
|
|
3351
|
+
});
|
|
3352
|
+
if (streamsSettlement) {
|
|
3353
|
+
await turn.writer.write(encodeStreamEvent({
|
|
3354
|
+
kind: "approval-settled",
|
|
3355
|
+
id: call.id,
|
|
3356
|
+
status: "rejected",
|
|
3357
|
+
decidedBy: deciderRef,
|
|
3358
|
+
...decision.decidedVia !== void 0 ? {
|
|
3359
|
+
decidedVia: decision.decidedVia
|
|
3360
|
+
} : {},
|
|
3361
|
+
...decision.reason !== void 0 ? {
|
|
3362
|
+
reason: decision.reason
|
|
3363
|
+
} : {}
|
|
3364
|
+
}));
|
|
3365
|
+
}
|
|
3366
|
+
});
|
|
3175
3367
|
publishAgentToolCall({
|
|
3176
3368
|
runId: hooks.runId,
|
|
3177
3369
|
toolName: call.name,
|
|
@@ -3194,10 +3386,60 @@ async function runClaimedToolCall(turn, claimed) {
|
|
|
3194
3386
|
error: refusalNarrative(decision.reason)
|
|
3195
3387
|
};
|
|
3196
3388
|
}
|
|
3389
|
+
meta = {
|
|
3390
|
+
decidedBy: deciderRef,
|
|
3391
|
+
...decision.decidedVia !== void 0 ? {
|
|
3392
|
+
decidedVia: decision.decidedVia
|
|
3393
|
+
} : {},
|
|
3394
|
+
...decision.remember === true ? {
|
|
3395
|
+
remember: true
|
|
3396
|
+
} : {},
|
|
3397
|
+
streamed: streamsSettlement
|
|
3398
|
+
};
|
|
3197
3399
|
}
|
|
3198
|
-
return recordToolOutcome(turn, claimed, await invokeClaimedTool(turn, claimed), deciderRef);
|
|
3400
|
+
return recordToolOutcome(turn, claimed, await invokeClaimedTool(turn, claimed), deciderRef, meta);
|
|
3199
3401
|
}
|
|
3200
3402
|
__name(runClaimedToolCall, "runClaimedToolCall");
|
|
3403
|
+
async function expireToolCall(turn, claimed) {
|
|
3404
|
+
const { deps, hooks } = turn;
|
|
3405
|
+
const { call } = claimed;
|
|
3406
|
+
await hooks.step(`persist:toolreject:${call.id}`, async () => {
|
|
3407
|
+
await deps.store.updateToolCall({
|
|
3408
|
+
toolCallId: call.id,
|
|
3409
|
+
status: "expired",
|
|
3410
|
+
error: APPROVAL_EXPIRED_REASON
|
|
3411
|
+
});
|
|
3412
|
+
await turn.writer.write(encodeStreamEvent({
|
|
3413
|
+
kind: "approval-settled",
|
|
3414
|
+
id: call.id,
|
|
3415
|
+
status: "expired"
|
|
3416
|
+
}));
|
|
3417
|
+
});
|
|
3418
|
+
publishAgentToolCall({
|
|
3419
|
+
runId: hooks.runId,
|
|
3420
|
+
toolName: call.name,
|
|
3421
|
+
toolType: "action",
|
|
3422
|
+
status: "rejected"
|
|
3423
|
+
});
|
|
3424
|
+
return {
|
|
3425
|
+
id: call.id,
|
|
3426
|
+
name: call.name,
|
|
3427
|
+
output: {
|
|
3428
|
+
rejected: true,
|
|
3429
|
+
expired: true,
|
|
3430
|
+
reason: APPROVAL_EXPIRED_REASON
|
|
3431
|
+
},
|
|
3432
|
+
denied: true,
|
|
3433
|
+
expired: true,
|
|
3434
|
+
error: expiryNarrative()
|
|
3435
|
+
};
|
|
3436
|
+
}
|
|
3437
|
+
__name(expireToolCall, "expireToolCall");
|
|
3438
|
+
var APPROVAL_EXPIRED_REASON = "approval expired";
|
|
3439
|
+
function expiryNarrative() {
|
|
3440
|
+
return "This action needed approval, and the approval request expired before anyone decided. Nothing ran and nothing changed. Do not run it again on your own; tell the person it was not approved in time and ask whether they still want it.";
|
|
3441
|
+
}
|
|
3442
|
+
__name(expiryNarrative, "expiryNarrative");
|
|
3201
3443
|
function outputFrame(result) {
|
|
3202
3444
|
if (result.denied === true) {
|
|
3203
3445
|
const reason = refusalReason(result);
|
|
@@ -3870,6 +4112,7 @@ export {
|
|
|
3870
4112
|
AGENT_SPAN_EVENTS,
|
|
3871
4113
|
AGENT_STORE,
|
|
3872
4114
|
AGENT_TOOL_REGISTRY,
|
|
4115
|
+
APPROVAL_EXPIRED_REASON,
|
|
3873
4116
|
ASK_TOOL_DESCRIPTION,
|
|
3874
4117
|
ASK_TOOL_NAME,
|
|
3875
4118
|
AgentRegistry,
|
|
@@ -3884,6 +4127,7 @@ export {
|
|
|
3884
4127
|
DEFAULT_STRUCTURED_OUTPUT_INSTRUCTION,
|
|
3885
4128
|
DEFAULT_TOOL_TRANSIENT_RETRY_ATTEMPTS,
|
|
3886
4129
|
DEFAULT_TOOL_TRANSIENT_RETRY_BACKOFF_MS,
|
|
4130
|
+
DefaultApprovalPolicy,
|
|
3887
4131
|
DefaultRolesPolicy,
|
|
3888
4132
|
GLOBAL_SCOPE,
|
|
3889
4133
|
MAX_ASK_QUESTIONS,
|
|
@@ -3892,6 +4136,7 @@ export {
|
|
|
3892
4136
|
QuotaExceededError,
|
|
3893
4137
|
REMEMBER_TOOL_DESCRIPTION,
|
|
3894
4138
|
REMEMBER_TOOL_NAME,
|
|
4139
|
+
REQUESTER_APPROVER,
|
|
3895
4140
|
RunCancelledError,
|
|
3896
4141
|
SKILL_TOOL_DESCRIPTION,
|
|
3897
4142
|
SKILL_TOOL_NAME,
|
|
@@ -3919,6 +4164,7 @@ export {
|
|
|
3919
4164
|
createIncrementalGate,
|
|
3920
4165
|
dayBoundsUtc,
|
|
3921
4166
|
decodeStreamEvent,
|
|
4167
|
+
defaultCanDecide,
|
|
3922
4168
|
defaultScopeResolver,
|
|
3923
4169
|
detachedDelivered,
|
|
3924
4170
|
detachedStarted,
|
|
@@ -3939,6 +4185,7 @@ export {
|
|
|
3939
4185
|
isToolEnabled,
|
|
3940
4186
|
isTransientToolError,
|
|
3941
4187
|
loadSkill,
|
|
4188
|
+
mayDecideApproval,
|
|
3942
4189
|
memoryForgetVerdict,
|
|
3943
4190
|
memoryWriteVerdict,
|
|
3944
4191
|
normalizeDelegation,
|
|
@@ -3984,6 +4231,7 @@ export {
|
|
|
3984
4231
|
staticSkillProvider,
|
|
3985
4232
|
summarizeWithModel,
|
|
3986
4233
|
tenantScope,
|
|
4234
|
+
toolCallApprovalFromRow,
|
|
3987
4235
|
traceLlmTurn,
|
|
3988
4236
|
traceToolExecution,
|
|
3989
4237
|
truncateDetailContent,
|