@dudousxd/nestjs-agent-core 0.13.0 → 0.15.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 +1 -1
- package/dist/index.cjs +47 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +22 -7
- package/dist/index.d.ts +22 -7
- package/dist/index.js +47 -8
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -2614,9 +2614,9 @@ declare function tenantScope(tenantRef: string): string;
|
|
|
2614
2614
|
*
|
|
2615
2615
|
* A HOST-SUPPLIED FUNCTION rather than an enum this library owns, because the axes a deployment
|
|
2616
2616
|
* scopes by are the deployment's own. `Actor` gives an id and a tenant; it does not give a sector, a
|
|
2617
|
-
*
|
|
2617
|
+
* region, a warehouse, a shift — and every one of those is a real axis in some consumer. An enum here
|
|
2618
2618
|
* would make each of them a schema change in a library that has no business knowing they exist,
|
|
2619
|
-
* while a token is a string a host mints for itself. Return `['sector:logistics', 'tenant:
|
|
2619
|
+
* while a token is a string a host mints for itself. Return `['sector:logistics', 'tenant:berlin',
|
|
2620
2620
|
* 'global']` and precedence follows, with nothing in this package edited.
|
|
2621
2621
|
*
|
|
2622
2622
|
* MUST be a pure function of its context. It runs inside the `skills:catalog` checkpoint and its
|
|
@@ -2915,7 +2915,7 @@ interface MemoryRecord {
|
|
|
2915
2915
|
/**
|
|
2916
2916
|
* Always-on: this fact is in the block whether or not the turn is about it. The difference between
|
|
2917
2917
|
* working memory and recall, drawn per record — "they report on the calendar year" must not depend
|
|
2918
|
-
* on the turn mentioning dates, while "they prefer the
|
|
2918
|
+
* on the turn mentioning dates, while "they prefer the kerbside dock" can wait until it comes up.
|
|
2919
2919
|
*
|
|
2920
2920
|
* A PROPERTY OF THE ROW, NOT OF A WRITE. This library reads it and never sets it, the same way it
|
|
2921
2921
|
* never mints an `id`: an agent deciding its own conclusions are always-on is an agent deciding
|
|
@@ -2997,7 +2997,7 @@ interface ListMemoriesInput {
|
|
|
2997
2997
|
*
|
|
2998
2998
|
* `scopes` GATES, AND IT GATES FIRST. A search that ranks before it filters is a cross-tenant leak
|
|
2999
2999
|
* wearing a relevance score: the nearest neighbour to "what is our rollback policy" is another
|
|
3000
|
-
*
|
|
3000
|
+
* tenant's rollback policy. Filter in the query, not after it. Records returned outside `scopes` are
|
|
3001
3001
|
* dropped rather than trusted, so a mistake here costs throughput rather than privacy — but the
|
|
3002
3002
|
* drop is a backstop, not the boundary.
|
|
3003
3003
|
*/
|
|
@@ -3470,6 +3470,16 @@ declare class ToolRegistry {
|
|
|
3470
3470
|
private readonly entries;
|
|
3471
3471
|
register(spec: ToolSpec, handler: ToolHandler): void;
|
|
3472
3472
|
has(name: string): boolean;
|
|
3473
|
+
/**
|
|
3474
|
+
* Give a name back, and report whether it was held. For an importer that registered tools on
|
|
3475
|
+
* someone else's behalf — the MCP client is the one in this repo — and has to hand back the ones
|
|
3476
|
+
* its source stopped offering.
|
|
3477
|
+
*
|
|
3478
|
+
* The registry cannot tell whether a caller owns a name, so it does not try: whoever registered a
|
|
3479
|
+
* name is responsible for tracking that it did. Unregistering a name it does not own would
|
|
3480
|
+
* silently take a tool away from whoever does.
|
|
3481
|
+
*/
|
|
3482
|
+
unregister(name: string): boolean;
|
|
3473
3483
|
spec(name: string): ToolSpec | undefined;
|
|
3474
3484
|
allSpecs(): ToolSpec[];
|
|
3475
3485
|
/**
|
|
@@ -3569,7 +3579,9 @@ interface AgentLoopDeps<TOutput = unknown> {
|
|
|
3569
3579
|
/**
|
|
3570
3580
|
* Enables always-on ("inject") RAG: before the turn, retrieve passages for the user message and
|
|
3571
3581
|
* augment the system prompt with them. Its presence IS inject mode — agentic (tool) retrieval sets
|
|
3572
|
-
* no retriever here (it rides a normal `read` tool). Undefined → no injection
|
|
3582
|
+
* no retriever here (it rides a normal `read` tool). Undefined → no injection, and no `retrieve`
|
|
3583
|
+
* position: which answer a RUN got is journaled (see {@link PromptStages}), so wiring one does not
|
|
3584
|
+
* move the checkpoints of a turn already in flight.
|
|
3573
3585
|
*/
|
|
3574
3586
|
retriever?: Retriever;
|
|
3575
3587
|
/** How many passages inject-mode retrieval requests. Undefined → 5. */
|
|
@@ -3673,7 +3685,9 @@ interface AgentLoopDeps<TOutput = unknown> {
|
|
|
3673
3685
|
/**
|
|
3674
3686
|
* Authored procedures the model may pull in when a task calls for one, resolved per turn against
|
|
3675
3687
|
* the actor's scopes — see `skills.ts`. Undefined → no catalog block, no `skill` tool, and a
|
|
3676
|
-
* turn's checkpoint sequence is byte-identical to one that never had the option
|
|
3688
|
+
* turn's checkpoint sequence is byte-identical to one that never had the option — including for a
|
|
3689
|
+
* turn that was already in flight when this was wired, because which answer a RUN got is journaled
|
|
3690
|
+
* (see {@link PromptStages}).
|
|
3677
3691
|
*
|
|
3678
3692
|
* HOW IT COMPOSES WITH THE OTHER FOUR THINGS THAT WRITE THE PROMPT. The system block is assembled
|
|
3679
3693
|
* in one fixed order — the agent's base prompt, then each `promptContributors` section, then
|
|
@@ -3692,7 +3706,8 @@ interface AgentLoopDeps<TOutput = unknown> {
|
|
|
3692
3706
|
* What the assistant has previously concluded about the actor and their organisation, resolved per
|
|
3693
3707
|
* turn against the same scope tokens skills use — see `memory.ts`. Undefined → no memory block, no
|
|
3694
3708
|
* `remember` tool, and a turn's checkpoint sequence is byte-identical to one that never had the
|
|
3695
|
-
* option
|
|
3709
|
+
* option — including for a turn that was already in flight when this was wired, because which
|
|
3710
|
+
* answer a RUN got is journaled (see {@link PromptStages}).
|
|
3696
3711
|
*
|
|
3697
3712
|
* WHERE IT SITS IN THE PROMPT. The system block is assembled most-durable-first: the agent's base
|
|
3698
3713
|
* prompt (the same for everyone, every turn), then `promptContributors`, then MEMORY (the same for
|
package/dist/index.d.ts
CHANGED
|
@@ -2614,9 +2614,9 @@ declare function tenantScope(tenantRef: string): string;
|
|
|
2614
2614
|
*
|
|
2615
2615
|
* A HOST-SUPPLIED FUNCTION rather than an enum this library owns, because the axes a deployment
|
|
2616
2616
|
* scopes by are the deployment's own. `Actor` gives an id and a tenant; it does not give a sector, a
|
|
2617
|
-
*
|
|
2617
|
+
* region, a warehouse, a shift — and every one of those is a real axis in some consumer. An enum here
|
|
2618
2618
|
* would make each of them a schema change in a library that has no business knowing they exist,
|
|
2619
|
-
* while a token is a string a host mints for itself. Return `['sector:logistics', 'tenant:
|
|
2619
|
+
* while a token is a string a host mints for itself. Return `['sector:logistics', 'tenant:berlin',
|
|
2620
2620
|
* 'global']` and precedence follows, with nothing in this package edited.
|
|
2621
2621
|
*
|
|
2622
2622
|
* MUST be a pure function of its context. It runs inside the `skills:catalog` checkpoint and its
|
|
@@ -2915,7 +2915,7 @@ interface MemoryRecord {
|
|
|
2915
2915
|
/**
|
|
2916
2916
|
* Always-on: this fact is in the block whether or not the turn is about it. The difference between
|
|
2917
2917
|
* working memory and recall, drawn per record — "they report on the calendar year" must not depend
|
|
2918
|
-
* on the turn mentioning dates, while "they prefer the
|
|
2918
|
+
* on the turn mentioning dates, while "they prefer the kerbside dock" can wait until it comes up.
|
|
2919
2919
|
*
|
|
2920
2920
|
* A PROPERTY OF THE ROW, NOT OF A WRITE. This library reads it and never sets it, the same way it
|
|
2921
2921
|
* never mints an `id`: an agent deciding its own conclusions are always-on is an agent deciding
|
|
@@ -2997,7 +2997,7 @@ interface ListMemoriesInput {
|
|
|
2997
2997
|
*
|
|
2998
2998
|
* `scopes` GATES, AND IT GATES FIRST. A search that ranks before it filters is a cross-tenant leak
|
|
2999
2999
|
* wearing a relevance score: the nearest neighbour to "what is our rollback policy" is another
|
|
3000
|
-
*
|
|
3000
|
+
* tenant's rollback policy. Filter in the query, not after it. Records returned outside `scopes` are
|
|
3001
3001
|
* dropped rather than trusted, so a mistake here costs throughput rather than privacy — but the
|
|
3002
3002
|
* drop is a backstop, not the boundary.
|
|
3003
3003
|
*/
|
|
@@ -3470,6 +3470,16 @@ declare class ToolRegistry {
|
|
|
3470
3470
|
private readonly entries;
|
|
3471
3471
|
register(spec: ToolSpec, handler: ToolHandler): void;
|
|
3472
3472
|
has(name: string): boolean;
|
|
3473
|
+
/**
|
|
3474
|
+
* Give a name back, and report whether it was held. For an importer that registered tools on
|
|
3475
|
+
* someone else's behalf — the MCP client is the one in this repo — and has to hand back the ones
|
|
3476
|
+
* its source stopped offering.
|
|
3477
|
+
*
|
|
3478
|
+
* The registry cannot tell whether a caller owns a name, so it does not try: whoever registered a
|
|
3479
|
+
* name is responsible for tracking that it did. Unregistering a name it does not own would
|
|
3480
|
+
* silently take a tool away from whoever does.
|
|
3481
|
+
*/
|
|
3482
|
+
unregister(name: string): boolean;
|
|
3473
3483
|
spec(name: string): ToolSpec | undefined;
|
|
3474
3484
|
allSpecs(): ToolSpec[];
|
|
3475
3485
|
/**
|
|
@@ -3569,7 +3579,9 @@ interface AgentLoopDeps<TOutput = unknown> {
|
|
|
3569
3579
|
/**
|
|
3570
3580
|
* Enables always-on ("inject") RAG: before the turn, retrieve passages for the user message and
|
|
3571
3581
|
* augment the system prompt with them. Its presence IS inject mode — agentic (tool) retrieval sets
|
|
3572
|
-
* no retriever here (it rides a normal `read` tool). Undefined → no injection
|
|
3582
|
+
* no retriever here (it rides a normal `read` tool). Undefined → no injection, and no `retrieve`
|
|
3583
|
+
* position: which answer a RUN got is journaled (see {@link PromptStages}), so wiring one does not
|
|
3584
|
+
* move the checkpoints of a turn already in flight.
|
|
3573
3585
|
*/
|
|
3574
3586
|
retriever?: Retriever;
|
|
3575
3587
|
/** How many passages inject-mode retrieval requests. Undefined → 5. */
|
|
@@ -3673,7 +3685,9 @@ interface AgentLoopDeps<TOutput = unknown> {
|
|
|
3673
3685
|
/**
|
|
3674
3686
|
* Authored procedures the model may pull in when a task calls for one, resolved per turn against
|
|
3675
3687
|
* the actor's scopes — see `skills.ts`. Undefined → no catalog block, no `skill` tool, and a
|
|
3676
|
-
* turn's checkpoint sequence is byte-identical to one that never had the option
|
|
3688
|
+
* turn's checkpoint sequence is byte-identical to one that never had the option — including for a
|
|
3689
|
+
* turn that was already in flight when this was wired, because which answer a RUN got is journaled
|
|
3690
|
+
* (see {@link PromptStages}).
|
|
3677
3691
|
*
|
|
3678
3692
|
* HOW IT COMPOSES WITH THE OTHER FOUR THINGS THAT WRITE THE PROMPT. The system block is assembled
|
|
3679
3693
|
* in one fixed order — the agent's base prompt, then each `promptContributors` section, then
|
|
@@ -3692,7 +3706,8 @@ interface AgentLoopDeps<TOutput = unknown> {
|
|
|
3692
3706
|
* What the assistant has previously concluded about the actor and their organisation, resolved per
|
|
3693
3707
|
* turn against the same scope tokens skills use — see `memory.ts`. Undefined → no memory block, no
|
|
3694
3708
|
* `remember` tool, and a turn's checkpoint sequence is byte-identical to one that never had the
|
|
3695
|
-
* option
|
|
3709
|
+
* option — including for a turn that was already in flight when this was wired, because which
|
|
3710
|
+
* answer a RUN got is journaled (see {@link PromptStages}).
|
|
3696
3711
|
*
|
|
3697
3712
|
* WHERE IT SITS IN THE PROMPT. The system block is assembled most-durable-first: the agent's base
|
|
3698
3713
|
* prompt (the same for everyone, every turn), then `promptContributors`, then MEMORY (the same for
|
package/dist/index.js
CHANGED
|
@@ -1746,6 +1746,18 @@ var ToolRegistry = class {
|
|
|
1746
1746
|
has(name) {
|
|
1747
1747
|
return this.entries.has(name);
|
|
1748
1748
|
}
|
|
1749
|
+
/**
|
|
1750
|
+
* Give a name back, and report whether it was held. For an importer that registered tools on
|
|
1751
|
+
* someone else's behalf — the MCP client is the one in this repo — and has to hand back the ones
|
|
1752
|
+
* its source stopped offering.
|
|
1753
|
+
*
|
|
1754
|
+
* The registry cannot tell whether a caller owns a name, so it does not try: whoever registered a
|
|
1755
|
+
* name is responsible for tracking that it did. Unregistering a name it does not own would
|
|
1756
|
+
* silently take a tool away from whoever does.
|
|
1757
|
+
*/
|
|
1758
|
+
unregister(name) {
|
|
1759
|
+
return this.entries.delete(name);
|
|
1760
|
+
}
|
|
1749
1761
|
spec(name) {
|
|
1750
1762
|
return this.entries.get(name)?.spec;
|
|
1751
1763
|
}
|
|
@@ -2059,7 +2071,12 @@ var MAX_DELEGATION_DEPTH = 5;
|
|
|
2059
2071
|
var DEFAULT_MAX_AGENT_APPEARANCES = 1;
|
|
2060
2072
|
function delegationRefusal(args) {
|
|
2061
2073
|
const { deps, input, targetAgent } = args;
|
|
2062
|
-
const ancestry =
|
|
2074
|
+
const ancestry = [
|
|
2075
|
+
...input.delegationPath ?? [],
|
|
2076
|
+
...input.agentName !== void 0 ? [
|
|
2077
|
+
input.agentName
|
|
2078
|
+
] : []
|
|
2079
|
+
];
|
|
2063
2080
|
const appearances = ancestry.filter((name) => name === targetAgent).length;
|
|
2064
2081
|
const maxAppearances = deps.maxAgentAppearances ?? DEFAULT_MAX_AGENT_APPEARANCES;
|
|
2065
2082
|
if (appearances >= maxAppearances) {
|
|
@@ -2594,6 +2611,27 @@ __name(runIntake, "runIntake");
|
|
|
2594
2611
|
var PARALLEL_TOOLS_PATCH = "agent:parallel-tools";
|
|
2595
2612
|
var CANCELLATION_PATCH = "agent:cancellation";
|
|
2596
2613
|
var SELECTED_HISTORY_PATCH = "agent:selected-history";
|
|
2614
|
+
var PROMPT_STAGES_PATCH = "agent:prompt-stages";
|
|
2615
|
+
async function resolvePromptStages(deps, hooks) {
|
|
2616
|
+
const configured = {
|
|
2617
|
+
memory: deps.memory !== void 0,
|
|
2618
|
+
retriever: deps.retriever !== void 0,
|
|
2619
|
+
skills: deps.skills !== void 0
|
|
2620
|
+
};
|
|
2621
|
+
return await (hooks.patched?.(PROMPT_STAGES_PATCH) ?? Promise.resolve(true)) ? hooks.step("run:prompt-stages", () => Promise.resolve(configured)) : configured;
|
|
2622
|
+
}
|
|
2623
|
+
__name(resolvePromptStages, "resolvePromptStages");
|
|
2624
|
+
var UNSERVED_MEMORY = {
|
|
2625
|
+
scopes: [],
|
|
2626
|
+
entries: [],
|
|
2627
|
+
omitted: 0,
|
|
2628
|
+
pinnedOmitted: 0
|
|
2629
|
+
};
|
|
2630
|
+
var UNSERVED_SKILLS = {
|
|
2631
|
+
scopes: [],
|
|
2632
|
+
entries: [],
|
|
2633
|
+
omitted: 0
|
|
2634
|
+
};
|
|
2597
2635
|
async function haltIfCancelled(hooks, cancellable, name) {
|
|
2598
2636
|
const observe = hooks.cancelled;
|
|
2599
2637
|
if (!cancellable || observe === void 0) {
|
|
@@ -3121,6 +3159,7 @@ async function runAgentLoop(deps, input, hooks) {
|
|
|
3121
3159
|
agentName: input.agentName
|
|
3122
3160
|
} : {}
|
|
3123
3161
|
});
|
|
3162
|
+
const stages = await resolvePromptStages(deps, hooks);
|
|
3124
3163
|
const startedAt = await hooks.step("run:started-at", () => Promise.resolve(Date.now()));
|
|
3125
3164
|
await hooks.step("persist:run:start", async () => {
|
|
3126
3165
|
const promptHash = createHash("sha256").update(system).digest("hex");
|
|
@@ -3138,9 +3177,9 @@ async function runAgentLoop(deps, input, hooks) {
|
|
|
3138
3177
|
});
|
|
3139
3178
|
});
|
|
3140
3179
|
let memoryDigest;
|
|
3141
|
-
if (
|
|
3180
|
+
if (stages.memory) {
|
|
3142
3181
|
const config = deps.memory;
|
|
3143
|
-
memoryDigest = await hooks.step("memory:digest", () => offerMemories({
|
|
3182
|
+
memoryDigest = await hooks.step("memory:digest", () => config === void 0 ? Promise.resolve(UNSERVED_MEMORY) : offerMemories({
|
|
3144
3183
|
config,
|
|
3145
3184
|
ctx: skillContext(input),
|
|
3146
3185
|
query: input.userText
|
|
@@ -3167,16 +3206,16 @@ ${block}`;
|
|
|
3167
3206
|
});
|
|
3168
3207
|
}
|
|
3169
3208
|
let injectedPassages;
|
|
3170
|
-
if (
|
|
3209
|
+
if (stages.retriever) {
|
|
3171
3210
|
const retriever = deps.retriever;
|
|
3172
3211
|
const topK = deps.retrievalTopK ?? 5;
|
|
3173
3212
|
const passages = await hooks.step("retrieve", () => spanned("retrieval", hooks.runId, {
|
|
3174
3213
|
runId: hooks.runId,
|
|
3175
3214
|
queryLength: input.userText.length,
|
|
3176
3215
|
topK
|
|
3177
|
-
}, () => retriever
|
|
3216
|
+
}, () => retriever?.retrieve(input.userText, {
|
|
3178
3217
|
topK
|
|
3179
|
-
}), (retrieved) => ({
|
|
3218
|
+
}) ?? Promise.resolve([]), (retrieved) => ({
|
|
3180
3219
|
count: retrieved.length
|
|
3181
3220
|
})));
|
|
3182
3221
|
if (passages.length > 0) {
|
|
@@ -3192,9 +3231,9 @@ ${buildContextBlock(passages)}`;
|
|
|
3192
3231
|
});
|
|
3193
3232
|
}
|
|
3194
3233
|
let skillOffer;
|
|
3195
|
-
if (
|
|
3234
|
+
if (stages.skills) {
|
|
3196
3235
|
const config = deps.skills;
|
|
3197
|
-
skillOffer = await hooks.step("skills:catalog", () => offerSkills(config, skillContext(input)));
|
|
3236
|
+
skillOffer = await hooks.step("skills:catalog", () => config === void 0 ? Promise.resolve(UNSERVED_SKILLS) : offerSkills(config, skillContext(input)));
|
|
3198
3237
|
const block = skillOffer.entries.length > 0 ? buildSkillsBlock(skillOffer.entries) : "";
|
|
3199
3238
|
if (block.length > 0) {
|
|
3200
3239
|
system = `${system}
|