@memberjunction/ai-agents 6.1.5 → 6.1.6

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.
Files changed (32) hide show
  1. package/dist/AgentRunner.d.ts +2 -0
  2. package/dist/AgentRunner.d.ts.map +1 -1
  3. package/dist/AgentRunner.js +32 -9
  4. package/dist/AgentRunner.js.map +1 -1
  5. package/dist/ConversationCompactionManager.d.ts +7 -1
  6. package/dist/ConversationCompactionManager.d.ts.map +1 -1
  7. package/dist/ConversationCompactionManager.js +4 -1
  8. package/dist/ConversationCompactionManager.js.map +1 -1
  9. package/dist/KnowledgeAgent.d.ts.map +1 -1
  10. package/dist/KnowledgeAgent.js +12 -7
  11. package/dist/KnowledgeAgent.js.map +1 -1
  12. package/dist/agent-types/loop-agent-type.d.ts +4 -2
  13. package/dist/agent-types/loop-agent-type.d.ts.map +1 -1
  14. package/dist/agent-types/loop-agent-type.js +20 -13
  15. package/dist/agent-types/loop-agent-type.js.map +1 -1
  16. package/dist/base-agent.d.ts +13 -0
  17. package/dist/base-agent.d.ts.map +1 -1
  18. package/dist/base-agent.js +69 -22
  19. package/dist/base-agent.js.map +1 -1
  20. package/dist/index.d.ts +1 -1
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +1 -1
  23. package/dist/index.js.map +1 -1
  24. package/dist/native-tools/json-argument.d.ts +41 -0
  25. package/dist/native-tools/json-argument.d.ts.map +1 -0
  26. package/dist/native-tools/json-argument.js +79 -0
  27. package/dist/native-tools/json-argument.js.map +1 -0
  28. package/dist/realtime/realtime-client-session-service.d.ts +58 -7
  29. package/dist/realtime/realtime-client-session-service.d.ts.map +1 -1
  30. package/dist/realtime/realtime-client-session-service.js +71 -11
  31. package/dist/realtime/realtime-client-session-service.js.map +1 -1
  32. package/package.json +18 -18
@@ -18,9 +18,9 @@ import { looksLikeLoopEnvelope } from './native-tools/dual-channel.js';
18
18
  import { Metadata, RunView, LogStatus, LogStatusEx, LogError, LogErrorEx, IsVerboseLoggingEnabled, DatabaseProviderBase } from '@memberjunction/core';
19
19
  import { AgentRunWatchdog } from './agent-run-watchdog.js';
20
20
  import { AIPromptRunner, GetToolCallingDecision } from '@memberjunction/ai-prompts';
21
- import { BaseRealtimeModel, GetAIAPIKey } from '@memberjunction/ai';
21
+ import { BaseRealtimeModel, GetAIAPIKey, CredentialScopeAllows } from '@memberjunction/ai';
22
22
  import { BaseAgentType } from './agent-types/base-agent-type.js';
23
- import { CopyScalarsAndArrays, JSONValidator, MJGlobal, SafeExpressionEvaluator, UUIDsEqual, EscapeSQLString } from '@memberjunction/global';
23
+ import { CopyScalarsAndArrays, JSONValidator, MJGlobal, SafeExpressionEvaluator, UUIDsEqual, EscapeSQLString, IsValidUUID } from '@memberjunction/global';
24
24
  // token optimization via @memberjunction/context-crush (SmartCrusher/CacheAligner-inspired)
25
25
  import { CrushJSON, DescribeCrush, PartitionStablePrefix } from '@memberjunction/context-crush';
26
26
  // AST-aware code reduction (CodeCompressor-inspired) — opt-in per agent type
@@ -1604,6 +1604,7 @@ export class BaseAgent {
1604
1604
  ? (params.data?.realtimeSelfNames).filter((n) => typeof n === 'string')
1605
1605
  : undefined;
1606
1606
  return {
1607
+ CredentialScope: params.CredentialScope,
1607
1608
  CoAgent: params.agent,
1608
1609
  TargetAgentID: targetID,
1609
1610
  AgentSessionID: params.data?.agentSessionId ?? '',
@@ -1649,7 +1650,8 @@ export class BaseAgent {
1649
1650
  if (!vendor) {
1650
1651
  continue;
1651
1652
  }
1652
- const apiKey = GetAIAPIKey(vendor.DriverClass);
1653
+ // Realtime only ever uses the platform key here, so a scope that rules that out has no key.
1654
+ const apiKey = CredentialScopeAllows(params.CredentialScope, 'Environment') ? GetAIAPIKey(vendor.DriverClass) : undefined;
1653
1655
  if (!apiKey) {
1654
1656
  continue;
1655
1657
  }
@@ -1926,6 +1928,7 @@ export class BaseAgent {
1926
1928
  parentDepth: this._depth,
1927
1929
  configurationId: params.configurationId,
1928
1930
  apiKeys: params.apiKeys,
1931
+ CredentialScope: params.CredentialScope,
1929
1932
  data: params.data,
1930
1933
  verbose: params.verbose,
1931
1934
  // Progress streams BOTH to the runner's narration consumer (request.OnProgress —
@@ -2449,6 +2452,13 @@ export class BaseAgent {
2449
2452
  this.logStatus(`🔄 Executing step ${stepCount + 1} for agent '${params.agent.Name}'`, true, params);
2450
2453
  const nextStep = await this.executeNextStep(params, config, currentNextStep, stepCount);
2451
2454
  stepCount++;
2455
+ // A failed step cut short by a cancellation is not a failure: end the run as cancelled
2456
+ // before the step is counted toward the consecutive-failure limit, which would end it as
2457
+ // Failed. A step that finished is kept: a final answer the user stopped too late to
2458
+ // prevent still completes the run.
2459
+ if (nextStep.step === 'Failed' && params.cancellationToken?.aborted) {
2460
+ throw new Error('Cancelled during execution');
2461
+ }
2452
2462
  // Promote any media outputs from this step to the agent's outputs
2453
2463
  if (nextStep.promoteMediaOutputs && nextStep.promoteMediaOutputs.length > 0) {
2454
2464
  this.promoteMediaOutputs(nextStep.promoteMediaOutputs);
@@ -3381,6 +3391,7 @@ export class BaseAgent {
3381
3391
  if (params.apiKeys && params.apiKeys.length > 0) {
3382
3392
  childPromptParams.apiKeys = params.apiKeys;
3383
3393
  }
3394
+ childPromptParams.CredentialScope = params.CredentialScope;
3384
3395
  // Pass through configurationId to both parent and child prompts if provided
3385
3396
  if (params.configurationId) {
3386
3397
  promptParams.configurationId = params.configurationId;
@@ -3416,6 +3427,10 @@ export class BaseAgent {
3416
3427
  promptParams.apiKeys = params.apiKeys;
3417
3428
  this.logStatus(`🔑 Using ${params.apiKeys.length} API key(s) provided at runtime`, true, params);
3418
3429
  }
3430
+ promptParams.CredentialScope = params.CredentialScope;
3431
+ if (!CredentialScopeAllows(params.CredentialScope, 'Environment')) {
3432
+ this.logStatus(`🔒 Credential scope is ${params.CredentialScope}: the platform's environment API keys will not be used`, true, params);
3433
+ }
3419
3434
  // Thread the per-request provider so prompt run records are saved through the isolated provider
3420
3435
  promptParams.provider = params.provider || this._activeProvider;
3421
3436
  // Overlay scope-resolved run settings (model / vendor / configuration / effort / sampling
@@ -5318,10 +5333,10 @@ The context is now within limits. Please retry your request with the recovered c
5318
5333
  throw new Error(`The '${BaseAgent.SummarizeRangePromptName}' system prompt is not present in this environment`);
5319
5334
  }
5320
5335
  const promptParams = new AIPromptParams();
5336
+ Object.assign(promptParams, this.runPromptExecutionScope(params));
5321
5337
  promptParams.prompt = prompt;
5322
5338
  // Keys are the summarize-range.template.md contract ({{ lens }}, {{ messages }})
5323
5339
  promptParams.data = { lens, messages: rangeText };
5324
- promptParams.contextUser = params.contextUser;
5325
5340
  promptParams.agentId = params.agent.ID;
5326
5341
  const result = await this._promptRunner.ExecutePrompt(promptParams);
5327
5342
  const text = ExtractPromptResultText(result);
@@ -6187,7 +6202,10 @@ The context is now within limits. Please retry your request with the recovered c
6187
6202
  ContextUser: contextUser,
6188
6203
  Filters: [],
6189
6204
  SkipActionLog: false,
6190
- Context: actionContext
6205
+ Context: actionContext,
6206
+ // AICredentialScope → actions-base's RuntimeCredentialScope mirror: a value added to the
6207
+ // former and not the latter fails to compile here, so the two cannot drift apart.
6208
+ CredentialScope: params.CredentialScope
6191
6209
  });
6192
6210
  if (result.Success) {
6193
6211
  this.logStatus(` ✅ Action '${action.name}' completed successfully`, true, params);
@@ -6418,6 +6436,7 @@ The context is now within limits. Please retry your request with the recovered c
6418
6436
  configurationId: params.configurationId, // propagate configuration ID to sub-agent
6419
6437
  effortLevel: params.effortLevel, // propagate effort level to sub-agent
6420
6438
  apiKeys: params.apiKeys, // propagate API keys to sub-agent
6439
+ CredentialScope: params.CredentialScope, // a sub-agent may not spend keys its parent could not
6421
6440
  inputArtifacts: params.inputArtifacts, // propagate input artifacts so sub-agents inherit the parent's artifact manifest + tools (e.g. a Codesmith delegate can read a Data Snapshot the parent references)
6422
6441
  data: {
6423
6442
  ...params.data,
@@ -7068,6 +7087,16 @@ The context is now within limits. Please retry your request with the recovered c
7068
7087
  // For now, returning a placeholder
7069
7088
  return 'General';
7070
7089
  }
7090
+ /**
7091
+ * Throws unless `lastRunId` is absent or a UUID. The value can come from a client, and the run
7092
+ * initialization places it in `ExtraFilter` clauses (the payload lookup, {@link validateRunChain}
7093
+ * and {@link resolvePlanModeGate}).
7094
+ */
7095
+ assertLastRunIdIsUUID(lastRunId) {
7096
+ if (lastRunId && !IsValidUUID(lastRunId)) {
7097
+ throw new Error('Invalid lastRunId: expected the UUID of a prior AI Agent Run.');
7098
+ }
7099
+ }
7071
7100
  /**
7072
7101
  * Initializes the agent run tracking by creating MJAIAgentRunEntityExtended and setting up context.
7073
7102
  *
@@ -7075,6 +7104,7 @@ The context is now within limits. Please retry your request with the recovered c
7075
7104
  * @param {ExecuteAgentParams} params - The execution parameters
7076
7105
  */
7077
7106
  async initializeAgentRun(params) {
7107
+ this.assertLastRunIdIsUUID(params.lastRunId);
7078
7108
  // Handle autoPopulateLastRunPayload if requested
7079
7109
  let modifiedParams = params;
7080
7110
  if (params.lastRunId && params.autoPopulateLastRunPayload) {
@@ -8040,6 +8070,23 @@ The context is now within limits. Please retry your request with the recovered c
8040
8070
  if (promptResult.modelSelectionInfo) {
8041
8071
  this._lastModelSelectionInfo = promptResult.modelSelectionInfo;
8042
8072
  }
8073
+ // Check for cancellation after prompt execution — before the failure check, because a prompt
8074
+ // the caller cancelled comes back failed, and that is not a prompt failure. The step does not
8075
+ // terminate the loop: a terminating step would finalize the run as Failed. The loop's own
8076
+ // cancellation check, before the next step, ends the run as Cancelled.
8077
+ if (params.cancellationToken?.aborted) {
8078
+ if (stepEntity && payload) {
8079
+ stepEntity.PayloadAtEnd = this.serializePayloadAtEnd(payload);
8080
+ }
8081
+ await this.finalizeStepEntity(stepEntity, false, 'Cancelled during prompt execution');
8082
+ return {
8083
+ errorMessage: 'Cancelled during prompt execution',
8084
+ step: 'Failed',
8085
+ terminate: false,
8086
+ previousPayload: payload,
8087
+ newPayload: payload
8088
+ };
8089
+ }
8043
8090
  // Check if prompt execution failed
8044
8091
  if (!promptResult.success) {
8045
8092
  // CRITICAL FIX: Preserve payload before finalizing step
@@ -8068,22 +8115,6 @@ The context is now within limits. Please retry your request with the recovered c
8068
8115
  newPayload: payload
8069
8116
  };
8070
8117
  }
8071
- // Check for cancellation after prompt execution
8072
- if (params.cancellationToken?.aborted) {
8073
- // CRITICAL FIX: Preserve payload before finalizing step
8074
- if (stepEntity && payload) {
8075
- stepEntity.PayloadAtEnd = this.serializePayloadAtEnd(payload);
8076
- }
8077
- await this.finalizeStepEntity(stepEntity, false, 'Cancelled during prompt execution');
8078
- const cancelledResult = await this.createCancelledResult('Cancelled during prompt execution', params.contextUser);
8079
- return {
8080
- ...cancelledResult,
8081
- terminate: true,
8082
- step: 'Failed', // Cancelled is treated as failed
8083
- previousPayload: cancelledResult.payload,
8084
- newPayload: cancelledResult.payload // No changes, just return the same payload
8085
- };
8086
- }
8087
8118
  // Report decision processing progress
8088
8119
  this.safeOnProgress(params, {
8089
8120
  step: 'decision_processing',
@@ -12340,6 +12371,21 @@ The context is now within limits. Please retry your request with the recovered c
12340
12371
  LogError(`Post-turn cross-turn compaction error (contained): ${error instanceof Error ? error.message : error}`);
12341
12372
  });
12342
12373
  }
12374
+ /**
12375
+ * The {@link AIPromptExecutionScope} of a prompt this run starts outside the agent's own turn —
12376
+ * summarizing a range, compacting a message, compacting the conversation. Each built its params
12377
+ * with only `contextUser`, so it ran on the platform's keys and default configuration inside a
12378
+ * run on a customer's keys, and under a `'RuntimeOnly'` scope would have bypassed it.
12379
+ */
12380
+ runPromptExecutionScope(params) {
12381
+ return {
12382
+ contextUser: params.contextUser,
12383
+ provider: params.provider || this._activeProvider,
12384
+ configurationId: params.configurationId,
12385
+ apiKeys: params.apiKeys,
12386
+ CredentialScope: params.CredentialScope,
12387
+ };
12388
+ }
12343
12389
  /**
12344
12390
  * Runs one compaction pass and records it as a `StepType='Compaction'` run step —
12345
12391
  * TargetID = the summary prompt, TargetLogID = the summary AIPromptRun (the same ID
@@ -12358,6 +12404,7 @@ The context is now within limits. Please retry your request with the recovered c
12358
12404
  Budget: budget,
12359
12405
  ContextUser: params.contextUser,
12360
12406
  Provider: this.ProviderToUse,
12407
+ ExecutionScope: this.runPromptExecutionScope(params),
12361
12408
  EstimateTokens: (messages) => this.estimateConversationTokens(messages),
12362
12409
  Verbose: params.verbose,
12363
12410
  // The in-flight agent-response placeholder row: a post-turn pass runs while
@@ -12582,6 +12629,7 @@ The context is now within limits. Please retry your request with the recovered c
12582
12629
  const step = await this.createCompactionStep(prompt, message, params);
12583
12630
  // Execute summarization prompt
12584
12631
  const promptParams = new AIPromptParams();
12632
+ Object.assign(promptParams, this.runPromptExecutionScope(params));
12585
12633
  promptParams.prompt = prompt;
12586
12634
  promptParams.data = {
12587
12635
  originalContent,
@@ -12590,7 +12638,6 @@ The context is now within limits. Please retry your request with the recovered c
12590
12638
  messageType: message.metadata?.messageType || 'unknown',
12591
12639
  turnAdded: message.metadata?.turnAdded || 0
12592
12640
  };
12593
- promptParams.contextUser = params.contextUser;
12594
12641
  promptParams.agentId = params.agent.ID;
12595
12642
  const runner = new AIPromptRunner();
12596
12643
  const result = await runner.ExecutePrompt(promptParams);