@dudousxd/nestjs-agent-core 0.13.0 → 0.14.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/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
- * squadron, a base, a shift — and every one of those is a real axis in some consumer. An enum here
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:base-7',
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 shorter runway" can wait until it comes up.
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
- * base's rollback policy. Filter in the query, not after it. Records returned outside `scopes` are
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
  */
@@ -3569,7 +3569,9 @@ interface AgentLoopDeps<TOutput = unknown> {
3569
3569
  /**
3570
3570
  * Enables always-on ("inject") RAG: before the turn, retrieve passages for the user message and
3571
3571
  * 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.
3572
+ * no retriever here (it rides a normal `read` tool). Undefined → no injection, and no `retrieve`
3573
+ * position: which answer a RUN got is journaled (see {@link PromptStages}), so wiring one does not
3574
+ * move the checkpoints of a turn already in flight.
3573
3575
  */
3574
3576
  retriever?: Retriever;
3575
3577
  /** How many passages inject-mode retrieval requests. Undefined → 5. */
@@ -3673,7 +3675,9 @@ interface AgentLoopDeps<TOutput = unknown> {
3673
3675
  /**
3674
3676
  * Authored procedures the model may pull in when a task calls for one, resolved per turn against
3675
3677
  * 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.
3678
+ * turn's checkpoint sequence is byte-identical to one that never had the option — including for a
3679
+ * turn that was already in flight when this was wired, because which answer a RUN got is journaled
3680
+ * (see {@link PromptStages}).
3677
3681
  *
3678
3682
  * HOW IT COMPOSES WITH THE OTHER FOUR THINGS THAT WRITE THE PROMPT. The system block is assembled
3679
3683
  * in one fixed order — the agent's base prompt, then each `promptContributors` section, then
@@ -3692,7 +3696,8 @@ interface AgentLoopDeps<TOutput = unknown> {
3692
3696
  * What the assistant has previously concluded about the actor and their organisation, resolved per
3693
3697
  * turn against the same scope tokens skills use — see `memory.ts`. Undefined → no memory block, no
3694
3698
  * `remember` tool, and a turn's checkpoint sequence is byte-identical to one that never had the
3695
- * option.
3699
+ * option — including for a turn that was already in flight when this was wired, because which
3700
+ * answer a RUN got is journaled (see {@link PromptStages}).
3696
3701
  *
3697
3702
  * WHERE IT SITS IN THE PROMPT. The system block is assembled most-durable-first: the agent's base
3698
3703
  * 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
- * squadron, a base, a shift — and every one of those is a real axis in some consumer. An enum here
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:base-7',
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 shorter runway" can wait until it comes up.
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
- * base's rollback policy. Filter in the query, not after it. Records returned outside `scopes` are
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
  */
@@ -3569,7 +3569,9 @@ interface AgentLoopDeps<TOutput = unknown> {
3569
3569
  /**
3570
3570
  * Enables always-on ("inject") RAG: before the turn, retrieve passages for the user message and
3571
3571
  * 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.
3572
+ * no retriever here (it rides a normal `read` tool). Undefined → no injection, and no `retrieve`
3573
+ * position: which answer a RUN got is journaled (see {@link PromptStages}), so wiring one does not
3574
+ * move the checkpoints of a turn already in flight.
3573
3575
  */
3574
3576
  retriever?: Retriever;
3575
3577
  /** How many passages inject-mode retrieval requests. Undefined → 5. */
@@ -3673,7 +3675,9 @@ interface AgentLoopDeps<TOutput = unknown> {
3673
3675
  /**
3674
3676
  * Authored procedures the model may pull in when a task calls for one, resolved per turn against
3675
3677
  * 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.
3678
+ * turn's checkpoint sequence is byte-identical to one that never had the option — including for a
3679
+ * turn that was already in flight when this was wired, because which answer a RUN got is journaled
3680
+ * (see {@link PromptStages}).
3677
3681
  *
3678
3682
  * HOW IT COMPOSES WITH THE OTHER FOUR THINGS THAT WRITE THE PROMPT. The system block is assembled
3679
3683
  * in one fixed order — the agent's base prompt, then each `promptContributors` section, then
@@ -3692,7 +3696,8 @@ interface AgentLoopDeps<TOutput = unknown> {
3692
3696
  * What the assistant has previously concluded about the actor and their organisation, resolved per
3693
3697
  * turn against the same scope tokens skills use — see `memory.ts`. Undefined → no memory block, no
3694
3698
  * `remember` tool, and a turn's checkpoint sequence is byte-identical to one that never had the
3695
- * option.
3699
+ * option — including for a turn that was already in flight when this was wired, because which
3700
+ * answer a RUN got is journaled (see {@link PromptStages}).
3696
3701
  *
3697
3702
  * WHERE IT SITS IN THE PROMPT. The system block is assembled most-durable-first: the agent's base
3698
3703
  * prompt (the same for everyone, every turn), then `promptContributors`, then MEMORY (the same for
package/dist/index.js CHANGED
@@ -2059,7 +2059,12 @@ var MAX_DELEGATION_DEPTH = 5;
2059
2059
  var DEFAULT_MAX_AGENT_APPEARANCES = 1;
2060
2060
  function delegationRefusal(args) {
2061
2061
  const { deps, input, targetAgent } = args;
2062
- const ancestry = input.delegationPath ?? [];
2062
+ const ancestry = [
2063
+ ...input.delegationPath ?? [],
2064
+ ...input.agentName !== void 0 ? [
2065
+ input.agentName
2066
+ ] : []
2067
+ ];
2063
2068
  const appearances = ancestry.filter((name) => name === targetAgent).length;
2064
2069
  const maxAppearances = deps.maxAgentAppearances ?? DEFAULT_MAX_AGENT_APPEARANCES;
2065
2070
  if (appearances >= maxAppearances) {
@@ -2594,6 +2599,27 @@ __name(runIntake, "runIntake");
2594
2599
  var PARALLEL_TOOLS_PATCH = "agent:parallel-tools";
2595
2600
  var CANCELLATION_PATCH = "agent:cancellation";
2596
2601
  var SELECTED_HISTORY_PATCH = "agent:selected-history";
2602
+ var PROMPT_STAGES_PATCH = "agent:prompt-stages";
2603
+ async function resolvePromptStages(deps, hooks) {
2604
+ const configured = {
2605
+ memory: deps.memory !== void 0,
2606
+ retriever: deps.retriever !== void 0,
2607
+ skills: deps.skills !== void 0
2608
+ };
2609
+ return await (hooks.patched?.(PROMPT_STAGES_PATCH) ?? Promise.resolve(true)) ? hooks.step("run:prompt-stages", () => Promise.resolve(configured)) : configured;
2610
+ }
2611
+ __name(resolvePromptStages, "resolvePromptStages");
2612
+ var UNSERVED_MEMORY = {
2613
+ scopes: [],
2614
+ entries: [],
2615
+ omitted: 0,
2616
+ pinnedOmitted: 0
2617
+ };
2618
+ var UNSERVED_SKILLS = {
2619
+ scopes: [],
2620
+ entries: [],
2621
+ omitted: 0
2622
+ };
2597
2623
  async function haltIfCancelled(hooks, cancellable, name) {
2598
2624
  const observe = hooks.cancelled;
2599
2625
  if (!cancellable || observe === void 0) {
@@ -3121,6 +3147,7 @@ async function runAgentLoop(deps, input, hooks) {
3121
3147
  agentName: input.agentName
3122
3148
  } : {}
3123
3149
  });
3150
+ const stages = await resolvePromptStages(deps, hooks);
3124
3151
  const startedAt = await hooks.step("run:started-at", () => Promise.resolve(Date.now()));
3125
3152
  await hooks.step("persist:run:start", async () => {
3126
3153
  const promptHash = createHash("sha256").update(system).digest("hex");
@@ -3138,9 +3165,9 @@ async function runAgentLoop(deps, input, hooks) {
3138
3165
  });
3139
3166
  });
3140
3167
  let memoryDigest;
3141
- if (deps.memory !== void 0) {
3168
+ if (stages.memory) {
3142
3169
  const config = deps.memory;
3143
- memoryDigest = await hooks.step("memory:digest", () => offerMemories({
3170
+ memoryDigest = await hooks.step("memory:digest", () => config === void 0 ? Promise.resolve(UNSERVED_MEMORY) : offerMemories({
3144
3171
  config,
3145
3172
  ctx: skillContext(input),
3146
3173
  query: input.userText
@@ -3167,16 +3194,16 @@ ${block}`;
3167
3194
  });
3168
3195
  }
3169
3196
  let injectedPassages;
3170
- if (deps.retriever !== void 0) {
3197
+ if (stages.retriever) {
3171
3198
  const retriever = deps.retriever;
3172
3199
  const topK = deps.retrievalTopK ?? 5;
3173
3200
  const passages = await hooks.step("retrieve", () => spanned("retrieval", hooks.runId, {
3174
3201
  runId: hooks.runId,
3175
3202
  queryLength: input.userText.length,
3176
3203
  topK
3177
- }, () => retriever.retrieve(input.userText, {
3204
+ }, () => retriever?.retrieve(input.userText, {
3178
3205
  topK
3179
- }), (retrieved) => ({
3206
+ }) ?? Promise.resolve([]), (retrieved) => ({
3180
3207
  count: retrieved.length
3181
3208
  })));
3182
3209
  if (passages.length > 0) {
@@ -3192,9 +3219,9 @@ ${buildContextBlock(passages)}`;
3192
3219
  });
3193
3220
  }
3194
3221
  let skillOffer;
3195
- if (deps.skills !== void 0) {
3222
+ if (stages.skills) {
3196
3223
  const config = deps.skills;
3197
- skillOffer = await hooks.step("skills:catalog", () => offerSkills(config, skillContext(input)));
3224
+ skillOffer = await hooks.step("skills:catalog", () => config === void 0 ? Promise.resolve(UNSERVED_SKILLS) : offerSkills(config, skillContext(input)));
3198
3225
  const block = skillOffer.entries.length > 0 ? buildSkillsBlock(skillOffer.entries) : "";
3199
3226
  if (block.length > 0) {
3200
3227
  system = `${system}