@memberjunction/server 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.
- package/dist/.tsbuildinfo +1 -1
- package/dist/agentSessions/SessionManager.d.ts +5 -2
- package/dist/agentSessions/SessionManager.d.ts.map +1 -1
- package/dist/agentSessions/SessionManager.js +17 -8
- package/dist/agentSessions/SessionManager.js.map +1 -1
- package/dist/agentSessions/SessionRunIDVerifier.d.ts +63 -0
- package/dist/agentSessions/SessionRunIDVerifier.d.ts.map +1 -0
- package/dist/agentSessions/SessionRunIDVerifier.js +129 -0
- package/dist/agentSessions/SessionRunIDVerifier.js.map +1 -0
- package/dist/agentSessions/index.d.ts +1 -0
- package/dist/agentSessions/index.d.ts.map +1 -1
- package/dist/agentSessions/index.js +1 -0
- package/dist/agentSessions/index.js.map +1 -1
- package/dist/auth/actionAuthorization.d.ts +40 -0
- package/dist/auth/actionAuthorization.d.ts.map +1 -0
- package/dist/auth/actionAuthorization.js +94 -0
- package/dist/auth/actionAuthorization.js.map +1 -0
- package/dist/auth/exampleNewUserSubClass.js +2 -1
- package/dist/auth/exampleNewUserSubClass.js.map +1 -1
- package/dist/auth/magicLink/MagicLinkService.d.ts.map +1 -1
- package/dist/auth/magicLink/MagicLinkService.js +6 -3
- package/dist/auth/magicLink/MagicLinkService.js.map +1 -1
- package/dist/auth/newUsers.d.ts.map +1 -1
- package/dist/auth/newUsers.js +15 -11
- package/dist/auth/newUsers.js.map +1 -1
- package/dist/context.d.ts +6 -0
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +13 -11
- package/dist/context.js.map +1 -1
- package/dist/generated/graphql-schemas/__mj.d.ts.map +1 -1
- package/dist/generated/graphql-schemas/__mj.js +3417 -3428
- package/dist/generated/graphql-schemas/__mj.js.map +1 -1
- package/dist/generic/CacheInvalidationResolver.d.ts +44 -8
- package/dist/generic/CacheInvalidationResolver.d.ts.map +1 -1
- package/dist/generic/CacheInvalidationResolver.js +59 -19
- package/dist/generic/CacheInvalidationResolver.js.map +1 -1
- package/dist/generic/ResolverBase.d.ts +95 -11
- package/dist/generic/ResolverBase.d.ts.map +1 -1
- package/dist/generic/ResolverBase.js +186 -76
- package/dist/generic/ResolverBase.js.map +1 -1
- package/dist/generic/RunViewResolver.d.ts.map +1 -1
- package/dist/generic/RunViewResolver.js +12 -0
- package/dist/generic/RunViewResolver.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -1
- package/dist/index.js.map +1 -1
- package/dist/isolatedProvider.d.ts +20 -0
- package/dist/isolatedProvider.d.ts.map +1 -0
- package/dist/isolatedProvider.js +22 -0
- package/dist/isolatedProvider.js.map +1 -0
- package/dist/multiTenancy/index.d.ts.map +1 -1
- package/dist/multiTenancy/index.js +22 -2
- package/dist/multiTenancy/index.js.map +1 -1
- package/dist/realtimeWidget/widgetGuestElevation.d.ts +4 -2
- package/dist/realtimeWidget/widgetGuestElevation.d.ts.map +1 -1
- package/dist/realtimeWidget/widgetGuestElevation.js +4 -2
- package/dist/realtimeWidget/widgetGuestElevation.js.map +1 -1
- package/dist/resolvers/ActionResolver.d.ts +31 -5
- package/dist/resolvers/ActionResolver.d.ts.map +1 -1
- package/dist/resolvers/ActionResolver.js +75 -14
- package/dist/resolvers/ActionResolver.js.map +1 -1
- package/dist/resolvers/AdhocQueryResolver.d.ts +28 -0
- package/dist/resolvers/AdhocQueryResolver.d.ts.map +1 -1
- package/dist/resolvers/AdhocQueryResolver.js +46 -0
- package/dist/resolvers/AdhocQueryResolver.js.map +1 -1
- package/dist/resolvers/DatasetResolver.d.ts +24 -3
- package/dist/resolvers/DatasetResolver.d.ts.map +1 -1
- package/dist/resolvers/DatasetResolver.js +57 -8
- package/dist/resolvers/DatasetResolver.js.map +1 -1
- package/dist/resolvers/EntityRecordNameResolver.d.ts +8 -23
- package/dist/resolvers/EntityRecordNameResolver.d.ts.map +1 -1
- package/dist/resolvers/EntityRecordNameResolver.js +11 -48
- package/dist/resolvers/EntityRecordNameResolver.js.map +1 -1
- package/dist/resolvers/FetchEntityVectorsResolver.js +2 -2
- package/dist/resolvers/FetchEntityVectorsResolver.js.map +1 -1
- package/dist/resolvers/GetDataContextDataResolver.d.ts +33 -7
- package/dist/resolvers/GetDataContextDataResolver.d.ts.map +1 -1
- package/dist/resolvers/GetDataContextDataResolver.js +117 -38
- package/dist/resolvers/GetDataContextDataResolver.js.map +1 -1
- package/dist/resolvers/GetDataResolver.d.ts.map +1 -1
- package/dist/resolvers/GetDataResolver.js +13 -1
- package/dist/resolvers/GetDataResolver.js.map +1 -1
- package/dist/resolvers/QuerySystemUserResolver.d.ts.map +1 -1
- package/dist/resolvers/QuerySystemUserResolver.js +2 -1
- package/dist/resolvers/QuerySystemUserResolver.js.map +1 -1
- package/dist/resolvers/RealtimeClientSessionResolver.d.ts +39 -16
- package/dist/resolvers/RealtimeClientSessionResolver.d.ts.map +1 -1
- package/dist/resolvers/RealtimeClientSessionResolver.js +84 -38
- package/dist/resolvers/RealtimeClientSessionResolver.js.map +1 -1
- package/dist/resolvers/RemoteBrowserActionResolver.d.ts +2 -0
- package/dist/resolvers/RemoteBrowserActionResolver.d.ts.map +1 -1
- package/dist/resolvers/RemoteBrowserActionResolver.js +5 -1
- package/dist/resolvers/RemoteBrowserActionResolver.js.map +1 -1
- package/dist/resolvers/RunTemplateResolver.d.ts.map +1 -1
- package/dist/resolvers/RunTemplateResolver.js +12 -11
- package/dist/resolvers/RunTemplateResolver.js.map +1 -1
- package/dist/resolvers/SearchKnowledgeResolver.d.ts +1 -0
- package/dist/resolvers/SearchKnowledgeResolver.d.ts.map +1 -1
- package/dist/resolvers/SearchKnowledgeResolver.js +5 -0
- package/dist/resolvers/SearchKnowledgeResolver.js.map +1 -1
- package/dist/resolvers/SearchKnowledgeSystemUserResolver.d.ts.map +1 -1
- package/dist/resolvers/SearchKnowledgeSystemUserResolver.js +1 -0
- package/dist/resolvers/SearchKnowledgeSystemUserResolver.js.map +1 -1
- package/dist/resolvers/SyncDataResolver.d.ts.map +1 -1
- package/dist/resolvers/SyncDataResolver.js +6 -2
- package/dist/resolvers/SyncDataResolver.js.map +1 -1
- package/dist/resolvers/VectorizeEntityResolver.d.ts +1 -1
- package/dist/resolvers/VectorizeEntityResolver.d.ts.map +1 -1
- package/dist/resolvers/VectorizeEntityResolver.js +14 -10
- package/dist/resolvers/VectorizeEntityResolver.js.map +1 -1
- package/dist/rest/ViewOperationsHandler.d.ts +3 -1
- package/dist/rest/ViewOperationsHandler.d.ts.map +1 -1
- package/dist/rest/ViewOperationsHandler.js +29 -17
- package/dist/rest/ViewOperationsHandler.js.map +1 -1
- package/dist/services/TaskGraphActionRunner.d.ts +8 -0
- package/dist/services/TaskGraphActionRunner.d.ts.map +1 -1
- package/dist/services/TaskGraphActionRunner.js +27 -1
- package/dist/services/TaskGraphActionRunner.js.map +1 -1
- package/package.json +92 -92
- package/src/__tests__/ActionResolver.authorization.test.ts +353 -0
- package/src/__tests__/AdhocQueryResolver.bugs.test.ts +4 -2
- package/src/__tests__/AdhocQueryResolver.sqlAuthorizer.test.ts +104 -0
- package/src/__tests__/DatasetResolver.itemFilters.test.ts +201 -0
- package/src/__tests__/EntityRecordNameResolver.fieldSecurity.test.ts +27 -72
- package/src/__tests__/EntityRecordNameResolver.rowSecurity.test.ts +152 -0
- package/src/__tests__/GetDataContextDataResolver.sqlItems.test.ts +416 -0
- package/src/__tests__/ListOperationsResolver.adhocScreen.test.ts +137 -0
- package/src/__tests__/RealtimeClientSessionResolver.configTamper.test.ts +383 -0
- package/src/__tests__/RealtimeClientSessionResolver.test.ts +106 -41
- package/src/__tests__/RemoteBrowserActionResolver.goalRunLink.test.ts +129 -0
- package/src/__tests__/ResolverBase.adhocReadScope.test.ts +227 -0
- package/src/__tests__/ResolverBase.aggregateScreen.test.ts +174 -0
- package/src/__tests__/ResolverBase.balancedClause.test.ts +155 -0
- package/src/__tests__/ResolverBase.clauseUnscopedRead.test.ts +127 -0
- package/src/__tests__/ResolverBase.filterEscaping.test.ts +24 -2
- package/src/__tests__/ResolverBase.isaPromotionCreate.test.ts +412 -0
- package/src/__tests__/RunTemplateResolver.test.ts +132 -0
- package/src/__tests__/RunViewResolver.cacheCheckScreen.test.ts +165 -0
- package/src/__tests__/SessionManager.test.ts +94 -17
- package/src/__tests__/SessionRunIDVerifier.test.ts +251 -0
- package/src/__tests__/TaskGraphActionRunner.durablePayload.test.ts +2 -0
- package/src/__tests__/TaskGraphActionRunner.storableOutputs.test.ts +76 -0
- package/src/__tests__/UpdateMJDataContextItem.oldValues.test.ts +220 -0
- package/src/__tests__/VectorizeEntityResolver.test.ts +106 -0
- package/src/__tests__/ViewOperationsHandler.clauseScreen.test.ts +157 -0
- package/src/__tests__/actionAuthorization.test.ts +130 -0
- package/src/__tests__/cacheInvalidationRecordData.test.ts +64 -0
- package/src/__tests__/isolatedProviderTransactions.test.ts +169 -0
- package/src/__tests__/magicLinkService.consume.test.ts +6 -0
- package/src/__tests__/magicLinkService.provisionLog.test.ts +5 -0
- package/src/__tests__/multiTenancy.postgresRewrite.test.ts +181 -0
- package/src/__tests__/multiTenancy.security.test.ts +51 -0
- package/src/__tests__/multiTenancy.test.ts +1 -1
- package/src/__tests__/newUsers.test.ts +62 -5
- package/src/agentSessions/SessionManager.ts +23 -25
- package/src/agentSessions/SessionRunIDVerifier.ts +171 -0
- package/src/agentSessions/index.ts +1 -0
- package/src/auth/actionAuthorization.ts +119 -0
- package/src/auth/exampleNewUserSubClass.ts +2 -2
- package/src/auth/magicLink/MagicLinkService.ts +6 -3
- package/src/auth/newUsers.ts +15 -11
- package/src/context.ts +14 -10
- package/src/generated/graphql-schemas/__mj.ts +3417 -3428
- package/src/generic/CacheInvalidationResolver.ts +74 -19
- package/src/generic/ResolverBase.ts +207 -80
- package/src/generic/RunViewResolver.ts +17 -0
- package/src/index.ts +9 -1
- package/src/isolatedProvider.ts +22 -0
- package/src/multiTenancy/index.ts +24 -2
- package/src/realtimeWidget/widgetGuestElevation.ts +4 -2
- package/src/resolvers/ActionResolver.ts +84 -21
- package/src/resolvers/AdhocQueryResolver.ts +49 -1
- package/src/resolvers/DatasetResolver.ts +70 -10
- package/src/resolvers/EntityRecordNameResolver.ts +11 -52
- package/src/resolvers/FetchEntityVectorsResolver.ts +2 -2
- package/src/resolvers/GetDataContextDataResolver.ts +139 -41
- package/src/resolvers/GetDataResolver.ts +14 -1
- package/src/resolvers/QuerySystemUserResolver.ts +2 -1
- package/src/resolvers/RealtimeClientSessionResolver.ts +103 -42
- package/src/resolvers/RemoteBrowserActionResolver.ts +11 -1
- package/src/resolvers/RunTemplateResolver.ts +13 -12
- package/src/resolvers/SearchKnowledgeResolver.ts +4 -0
- package/src/resolvers/SearchKnowledgeSystemUserResolver.ts +1 -0
- package/src/resolvers/SyncDataResolver.ts +6 -2
- package/src/resolvers/VectorizeEntityResolver.ts +16 -11
- package/src/resolvers/__tests__/GetDataResolver.validation.test.ts +95 -0
- package/src/rest/ViewOperationsHandler.ts +37 -18
- package/src/services/TaskGraphActionRunner.ts +29 -1
|
@@ -242,13 +242,44 @@ function makeSessionEntity(overrides: Partial<FakeSession> = {}): FakeSession {
|
|
|
242
242
|
};
|
|
243
243
|
}
|
|
244
244
|
|
|
245
|
-
/**
|
|
246
|
-
|
|
247
|
-
|
|
245
|
+
/** Co-agent observability and paused-run ids, as a voice session's Config holds them. */
|
|
246
|
+
const CO_RUN_ID = 'c0c0c0c0-0000-4000-8000-000000000001';
|
|
247
|
+
const PROMPT_RUN_ID = 'c0c0c0c0-0000-4000-8000-000000000002';
|
|
248
|
+
const PAUSED_RUN_ID = 'c0c0c0c0-0000-4000-8000-000000000003';
|
|
249
|
+
|
|
250
|
+
/** `RunView`/`RunViews` stubs for a provider. */
|
|
251
|
+
interface RunLookups {
|
|
252
|
+
RunView: ReturnType<typeof vi.fn>;
|
|
253
|
+
RunViews: ReturnType<typeof vi.fn>;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Answers the session run-id lookups: each id in `runIDs` is a run of the session, and
|
|
258
|
+
* `promptRunID` (when given) is the TargetLogID of the co-agent run's Prompt step.
|
|
259
|
+
*/
|
|
260
|
+
function sessionRunLookups(runIDs: string[], promptRunID?: string): RunLookups {
|
|
261
|
+
const runView = vi.fn(async (params: { EntityName?: string }) => {
|
|
262
|
+
if (params.EntityName === 'MJ: AI Agent Runs') {
|
|
263
|
+
return { Success: true, Results: runIDs.map((ID) => ({ ID })) };
|
|
264
|
+
}
|
|
265
|
+
if (params.EntityName === 'MJ: AI Agent Run Steps' && promptRunID) {
|
|
266
|
+
return { Success: true, Results: [{ ID: 'c0c0c0c0-0000-4000-8000-0000000000a1', StepType: 'Prompt', TargetLogID: promptRunID }] };
|
|
267
|
+
}
|
|
268
|
+
return { Success: true, Results: [] };
|
|
269
|
+
});
|
|
270
|
+
const runViews = vi.fn(async (paramsList: Array<{ EntityName?: string }>) => Promise.all(paramsList.map((params) => runView(params))));
|
|
271
|
+
return { RunView: runView, RunViews: runViews };
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/** Provider whose GetEntityObject returns a fixed entity per entity name, plus optional run-id lookups. */
|
|
275
|
+
function makeProvider(factory: (entityName: string) => FakeSession, lookups?: RunLookups): unknown {
|
|
276
|
+
return { GetEntityObject: vi.fn(async (name: string) => factory(name)), ...lookups };
|
|
248
277
|
}
|
|
249
278
|
|
|
250
279
|
beforeEach(() => {
|
|
251
280
|
hasPermissionMock.mockReset();
|
|
281
|
+
// Callers may run the agents in play unless a test says otherwise; relays re-check CanRun on the target.
|
|
282
|
+
hasPermissionMock.mockResolvedValue(true);
|
|
252
283
|
engineCoAgentsMock.mockReset();
|
|
253
284
|
engineCoAgentsMock.mockReturnValue([]);
|
|
254
285
|
engineChannelsMock.mockReset();
|
|
@@ -685,10 +716,12 @@ describe('RealtimeClientSessionResolver.ExecuteRealtimeSessionTool', () => {
|
|
|
685
716
|
});
|
|
686
717
|
|
|
687
718
|
it('reads the target + co-agent run id from the session config and returns ResultJson', async () => {
|
|
688
|
-
currentProvider = makeProvider(
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
719
|
+
currentProvider = makeProvider(
|
|
720
|
+
() =>
|
|
721
|
+
makeSessionEntity({
|
|
722
|
+
Config_: JSON.stringify({ targetAgentID: 'target-from-session', coAgentRunID: CO_RUN_ID }),
|
|
723
|
+
}),
|
|
724
|
+
sessionRunLookups([CO_RUN_ID]),
|
|
692
725
|
);
|
|
693
726
|
executeRelayedToolMock.mockResolvedValue({ ResultJson: '{"ok":true}', Success: true });
|
|
694
727
|
const resolver = makeResolver();
|
|
@@ -711,7 +744,7 @@ describe('RealtimeClientSessionResolver.ExecuteRealtimeSessionTool', () => {
|
|
|
711
744
|
// Target comes from the session, NOT the client.
|
|
712
745
|
expect(relayArg.TargetAgentID).toBe('target-from-session');
|
|
713
746
|
// Delegated run nests under the co-agent observability run from the session config.
|
|
714
|
-
expect(relayArg.ParentRunID).toBe(
|
|
747
|
+
expect(relayArg.ParentRunID).toBe(CO_RUN_ID);
|
|
715
748
|
expect(relayArg.Call).toEqual({ CallID: 'call-1', ToolName: 'invoke-target-agent', Arguments: '{"request":"do it"}' });
|
|
716
749
|
expect(heartbeatMock).toHaveBeenCalledWith('session-1', USER, currentProvider);
|
|
717
750
|
});
|
|
@@ -775,9 +808,9 @@ describe('RealtimeClientSessionResolver.ExecuteRealtimeSessionTool', () => {
|
|
|
775
808
|
|
|
776
809
|
it('consumes pendingFeedbackRunID as ResumeRunID and clears it on the next call', async () => {
|
|
777
810
|
const session = makeSessionEntity({
|
|
778
|
-
Config_: JSON.stringify({ targetAgentID: 'target-1', pendingFeedbackRunID:
|
|
811
|
+
Config_: JSON.stringify({ targetAgentID: 'target-1', pendingFeedbackRunID: PAUSED_RUN_ID }),
|
|
779
812
|
});
|
|
780
|
-
currentProvider = makeProvider(() => session);
|
|
813
|
+
currentProvider = makeProvider(() => session, sessionRunLookups([PAUSED_RUN_ID]));
|
|
781
814
|
// Resumed run completes (no new pause).
|
|
782
815
|
executeRelayedToolMock.mockResolvedValue({ ResultJson: '{"done":1}', Success: true });
|
|
783
816
|
const resolver = makeResolver();
|
|
@@ -786,7 +819,7 @@ describe('RealtimeClientSessionResolver.ExecuteRealtimeSessionTool', () => {
|
|
|
786
819
|
|
|
787
820
|
// The paused id was passed in to resume the run...
|
|
788
821
|
const relayArg = executeRelayedToolMock.mock.calls[0][0] as { ResumeRunID?: string };
|
|
789
|
-
expect(relayArg.ResumeRunID).toBe(
|
|
822
|
+
expect(relayArg.ResumeRunID).toBe(PAUSED_RUN_ID);
|
|
790
823
|
// ...and cleared from the session config afterward.
|
|
791
824
|
expect(JSON.parse(session.Config_ as string).pendingFeedbackRunID).toBeUndefined();
|
|
792
825
|
expect(session.Save).toHaveBeenCalled();
|
|
@@ -794,16 +827,16 @@ describe('RealtimeClientSessionResolver.ExecuteRealtimeSessionTool', () => {
|
|
|
794
827
|
|
|
795
828
|
it('re-stores a new pendingFeedbackRunID when a resumed run pauses again', async () => {
|
|
796
829
|
const session = makeSessionEntity({
|
|
797
|
-
Config_: JSON.stringify({ targetAgentID: 'target-1', pendingFeedbackRunID:
|
|
830
|
+
Config_: JSON.stringify({ targetAgentID: 'target-1', pendingFeedbackRunID: PAUSED_RUN_ID }),
|
|
798
831
|
});
|
|
799
|
-
currentProvider = makeProvider(() => session);
|
|
832
|
+
currentProvider = makeProvider(() => session, sessionRunLookups([PAUSED_RUN_ID]));
|
|
800
833
|
executeRelayedToolMock.mockResolvedValue({ ResultJson: '{"q":2}', Success: true, PausedRunID: 'paused-2' });
|
|
801
834
|
const resolver = makeResolver();
|
|
802
835
|
|
|
803
836
|
await resolver.ExecuteRealtimeSessionTool('session-1', 'call-3', 'invoke-target-agent', '{"request":"yes"}', makeCtx(), makePubSub());
|
|
804
837
|
|
|
805
838
|
const relayArg = executeRelayedToolMock.mock.calls[0][0] as { ResumeRunID?: string };
|
|
806
|
-
expect(relayArg.ResumeRunID).toBe(
|
|
839
|
+
expect(relayArg.ResumeRunID).toBe(PAUSED_RUN_ID);
|
|
807
840
|
expect(JSON.parse(session.Config_ as string).pendingFeedbackRunID).toBe('paused-2');
|
|
808
841
|
});
|
|
809
842
|
|
|
@@ -2292,10 +2325,11 @@ describe('RealtimeClientSessionResolver.RelayRealtimeUsage', () => {
|
|
|
2292
2325
|
}): { provider: unknown; promptRun: FakeSession } {
|
|
2293
2326
|
const session =
|
|
2294
2327
|
opts.session ??
|
|
2295
|
-
makeSessionEntity({ Config_: JSON.stringify({ targetAgentID: 'target-1', promptRunID:
|
|
2296
|
-
const promptRun = opts.promptRun ?? makeSessionEntity({ ID:
|
|
2328
|
+
makeSessionEntity({ Config_: JSON.stringify({ targetAgentID: 'target-1', coAgentRunID: CO_RUN_ID, promptRunID: PROMPT_RUN_ID }) });
|
|
2329
|
+
const promptRun = opts.promptRun ?? makeSessionEntity({ ID: PROMPT_RUN_ID, TokensPrompt: null, TokensCompletion: null, TokensUsed: null });
|
|
2297
2330
|
const provider = {
|
|
2298
2331
|
GetEntityObject: vi.fn(async (name: string) => (name === 'MJ: AI Prompt Runs' ? promptRun : session)),
|
|
2332
|
+
...sessionRunLookups([CO_RUN_ID], PROMPT_RUN_ID),
|
|
2299
2333
|
};
|
|
2300
2334
|
return { provider, promptRun };
|
|
2301
2335
|
}
|
|
@@ -2321,7 +2355,7 @@ describe('RealtimeClientSessionResolver.RelayRealtimeUsage', () => {
|
|
|
2321
2355
|
const ok = await resolver.RelayRealtimeUsage('session-1', 30, 5, makeCtx());
|
|
2322
2356
|
|
|
2323
2357
|
expect(ok).toBe(true);
|
|
2324
|
-
expect(promptRun.Load).toHaveBeenCalledWith(
|
|
2358
|
+
expect(promptRun.Load).toHaveBeenCalledWith(PROMPT_RUN_ID);
|
|
2325
2359
|
expect(promptRun.TokensPrompt).toBe(130);
|
|
2326
2360
|
expect(promptRun.TokensCompletion).toBe(45);
|
|
2327
2361
|
expect(promptRun.TokensUsed).toBe(175);
|
|
@@ -2418,7 +2452,7 @@ describe('RealtimeClientSessionResolver.RelayRealtimeUsage', () => {
|
|
|
2418
2452
|
const { provider, promptRun } = makeUsageProvider({
|
|
2419
2453
|
session: makeSessionEntity({
|
|
2420
2454
|
Status: 'Closed',
|
|
2421
|
-
Config_: JSON.stringify({ targetAgentID: 'target-1', promptRunID:
|
|
2455
|
+
Config_: JSON.stringify({ targetAgentID: 'target-1', coAgentRunID: CO_RUN_ID, promptRunID: PROMPT_RUN_ID }),
|
|
2422
2456
|
}),
|
|
2423
2457
|
});
|
|
2424
2458
|
currentProvider = provider;
|
|
@@ -2815,7 +2849,7 @@ describe('RealtimeClientSessionResolver — app awareness (applicationId / appCo
|
|
|
2815
2849
|
expect(relayArg.AllowedAgents?.map(a => a.agentId)).toEqual(['skip-1']);
|
|
2816
2850
|
});
|
|
2817
2851
|
|
|
2818
|
-
it('
|
|
2852
|
+
it('does not pass the directActions stored in the session config into ExecuteRelayedTool', async () => {
|
|
2819
2853
|
currentProvider = makeProvider(() =>
|
|
2820
2854
|
makeSessionEntity({
|
|
2821
2855
|
Config_: JSON.stringify({
|
|
@@ -2832,7 +2866,8 @@ describe('RealtimeClientSessionResolver — app awareness (applicationId / appCo
|
|
|
2832
2866
|
);
|
|
2833
2867
|
|
|
2834
2868
|
const relayArg = executeRelayedToolMock.mock.calls[0][0] as { DirectActions?: { enabled: boolean; actionNames: string[] } };
|
|
2835
|
-
|
|
2869
|
+
// The owner can edit Config, so the service takes direct actions from server-side state instead.
|
|
2870
|
+
expect(relayArg.DirectActions).toBeUndefined();
|
|
2836
2871
|
});
|
|
2837
2872
|
});
|
|
2838
2873
|
|
|
@@ -2925,7 +2960,7 @@ describe('RealtimeClientSessionResolver — scoped-anonymous elevation (issue #3
|
|
|
2925
2960
|
expect(executeRelayedToolMock.mock.calls[0][1]).toBe(ANON_USER);
|
|
2926
2961
|
});
|
|
2927
2962
|
|
|
2928
|
-
it('
|
|
2963
|
+
it('refuses a direct action from a scoped anonymous caller without dispatching it or writing a turn as the system user (#4791)', async () => {
|
|
2929
2964
|
const detail = makeSessionEntity({ ID: 'detail-1' });
|
|
2930
2965
|
currentProvider = {
|
|
2931
2966
|
GetEntityObject: vi.fn(async (name: string) =>
|
|
@@ -2935,17 +2970,16 @@ describe('RealtimeClientSessionResolver — scoped-anonymous elevation (issue #3
|
|
|
2935
2970
|
executeRelayedToolMock.mockResolvedValue({ ResultJson: '{"success":true}', Success: true });
|
|
2936
2971
|
const resolver = makeAnonResolver();
|
|
2937
2972
|
|
|
2938
|
-
await resolver.ExecuteRealtimeSessionTool(
|
|
2973
|
+
const out = await resolver.ExecuteRealtimeSessionTool(
|
|
2939
2974
|
'session-1', 'call-1', 'Some Direct Action', '{}', makeCtx(), makePubSub(),
|
|
2940
2975
|
);
|
|
2941
2976
|
|
|
2942
|
-
//
|
|
2943
|
-
expect(
|
|
2944
|
-
|
|
2945
|
-
|
|
2977
|
+
// Scope-limited callers get no direct actions, so nothing is dispatched, elevated or not…
|
|
2978
|
+
expect(JSON.parse(out)).toMatchObject({ success: false });
|
|
2979
|
+
expect(executeRelayedToolMock).not.toHaveBeenCalled();
|
|
2980
|
+
// …and no hidden Conversation Detail turn is written, least of all as the system user.
|
|
2946
2981
|
expect(getEntityObjectSpy()).not.toHaveBeenCalledWith('MJ: Conversation Details', SYSTEM_USER);
|
|
2947
|
-
expect(detail.Save).toHaveBeenCalled();
|
|
2948
|
-
expect(detail.UserID).toBe('anon-1');
|
|
2982
|
+
expect(detail.Save).not.toHaveBeenCalled();
|
|
2949
2983
|
});
|
|
2950
2984
|
|
|
2951
2985
|
it('writes the direct-action tool turn as the caller unchanged for a normal authenticated user', async () => {
|
|
@@ -2966,11 +3000,12 @@ describe('RealtimeClientSessionResolver — scoped-anonymous elevation (issue #3
|
|
|
2966
3000
|
it('accumulates relayed usage onto the prompt run under the SYSTEM user', async () => {
|
|
2967
3001
|
const session = makeSessionEntity({
|
|
2968
3002
|
UserID: 'anon-1',
|
|
2969
|
-
Config_: JSON.stringify({ targetAgentID: 'target-1', promptRunID:
|
|
3003
|
+
Config_: JSON.stringify({ targetAgentID: 'target-1', coAgentRunID: CO_RUN_ID, promptRunID: PROMPT_RUN_ID }),
|
|
2970
3004
|
});
|
|
2971
|
-
const promptRun = makeSessionEntity({ ID:
|
|
3005
|
+
const promptRun = makeSessionEntity({ ID: PROMPT_RUN_ID, TokensPrompt: null, TokensCompletion: null, TokensUsed: null });
|
|
2972
3006
|
currentProvider = {
|
|
2973
3007
|
GetEntityObject: vi.fn(async (name: string) => (name === 'MJ: AI Prompt Runs' ? promptRun : session)),
|
|
3008
|
+
...sessionRunLookups([CO_RUN_ID], PROMPT_RUN_ID),
|
|
2974
3009
|
};
|
|
2975
3010
|
const resolver = makeAnonResolver();
|
|
2976
3011
|
|
|
@@ -2985,9 +3020,9 @@ describe('RealtimeClientSessionResolver — scoped-anonymous elevation (issue #3
|
|
|
2985
3020
|
it('mirrors the transcript turn onto the prompt run as SYSTEM while the Conversation Detail stays the caller', async () => {
|
|
2986
3021
|
const session = makeSessionEntity({
|
|
2987
3022
|
UserID: 'anon-1',
|
|
2988
|
-
Config_: JSON.stringify({ targetAgentID: 'target-1', promptRunID:
|
|
3023
|
+
Config_: JSON.stringify({ targetAgentID: 'target-1', coAgentRunID: CO_RUN_ID, promptRunID: PROMPT_RUN_ID }),
|
|
2989
3024
|
});
|
|
2990
|
-
const promptRun = makeSessionEntity({ ID:
|
|
3025
|
+
const promptRun = makeSessionEntity({ ID: PROMPT_RUN_ID, Messages: null });
|
|
2991
3026
|
const detail = makeSessionEntity({ ID: 'detail-1' });
|
|
2992
3027
|
currentProvider = {
|
|
2993
3028
|
GetEntityObject: vi.fn(async (name: string) => {
|
|
@@ -2995,6 +3030,7 @@ describe('RealtimeClientSessionResolver — scoped-anonymous elevation (issue #3
|
|
|
2995
3030
|
if (name === 'MJ: Conversation Details') return detail;
|
|
2996
3031
|
return session;
|
|
2997
3032
|
}),
|
|
3033
|
+
...sessionRunLookups([CO_RUN_ID], PROMPT_RUN_ID),
|
|
2998
3034
|
};
|
|
2999
3035
|
const resolver = makeAnonResolver();
|
|
3000
3036
|
|
|
@@ -3011,11 +3047,12 @@ describe('RealtimeClientSessionResolver — scoped-anonymous elevation (issue #3
|
|
|
3011
3047
|
it('records the co-agent tool turn (RelayRealtimeToolTurn) under the SYSTEM user', async () => {
|
|
3012
3048
|
const session = makeSessionEntity({
|
|
3013
3049
|
UserID: 'anon-1',
|
|
3014
|
-
Config_: JSON.stringify({ targetAgentID: 'target-1', promptRunID:
|
|
3050
|
+
Config_: JSON.stringify({ targetAgentID: 'target-1', coAgentRunID: CO_RUN_ID, promptRunID: PROMPT_RUN_ID }),
|
|
3015
3051
|
});
|
|
3016
|
-
const promptRun = makeSessionEntity({ ID:
|
|
3052
|
+
const promptRun = makeSessionEntity({ ID: PROMPT_RUN_ID, Messages: null });
|
|
3017
3053
|
currentProvider = {
|
|
3018
3054
|
GetEntityObject: vi.fn(async (name: string) => (name === 'MJ: AI Prompt Runs' ? promptRun : session)),
|
|
3055
|
+
...sessionRunLookups([CO_RUN_ID], PROMPT_RUN_ID),
|
|
3019
3056
|
};
|
|
3020
3057
|
const resolver = makeAnonResolver();
|
|
3021
3058
|
|
|
@@ -3028,9 +3065,9 @@ describe('RealtimeClientSessionResolver — scoped-anonymous elevation (issue #3
|
|
|
3028
3065
|
it('writes the hidden co-agent tool turn (RelayRealtimeToolTurn) as the CALLER (#4791)', async () => {
|
|
3029
3066
|
const session = makeSessionEntity({
|
|
3030
3067
|
UserID: 'anon-1',
|
|
3031
|
-
Config_: JSON.stringify({ targetAgentID: 'target-1', promptRunID:
|
|
3068
|
+
Config_: JSON.stringify({ targetAgentID: 'target-1', coAgentRunID: CO_RUN_ID, promptRunID: PROMPT_RUN_ID }),
|
|
3032
3069
|
});
|
|
3033
|
-
const promptRun = makeSessionEntity({ ID:
|
|
3070
|
+
const promptRun = makeSessionEntity({ ID: PROMPT_RUN_ID, Messages: null });
|
|
3034
3071
|
const detail = makeSessionEntity({ ID: 'detail-3' });
|
|
3035
3072
|
currentProvider = {
|
|
3036
3073
|
GetEntityObject: vi.fn(async (name: string) => {
|
|
@@ -3038,6 +3075,7 @@ describe('RealtimeClientSessionResolver — scoped-anonymous elevation (issue #3
|
|
|
3038
3075
|
if (name === 'MJ: Conversation Details') return detail;
|
|
3039
3076
|
return session;
|
|
3040
3077
|
}),
|
|
3078
|
+
...sessionRunLookups([CO_RUN_ID], PROMPT_RUN_ID),
|
|
3041
3079
|
};
|
|
3042
3080
|
const resolver = makeAnonResolver();
|
|
3043
3081
|
|
|
@@ -3080,6 +3118,30 @@ describe('RealtimeClientSessionResolver — scoped-anonymous elevation (issue #3
|
|
|
3080
3118
|
expect(prepInput.UserID).toBe('anon-1');
|
|
3081
3119
|
});
|
|
3082
3120
|
|
|
3121
|
+
/** Starts a session as `resolver`'s caller and returns the input the prepare service received. */
|
|
3122
|
+
async function startAndCapturePrepInput(resolver: RealtimeClientSessionResolver, userID: string): Promise<{ ExcludeDirectActions?: boolean }> {
|
|
3123
|
+
currentProvider = makeProvider(() => makeSessionEntity({ UserID: userID }));
|
|
3124
|
+
createSessionMock.mockResolvedValue(makeSessionEntity({ ID: 'session-start', UserID: userID }));
|
|
3125
|
+
prepareClientSessionMock.mockResolvedValue({
|
|
3126
|
+
Success: true,
|
|
3127
|
+
ClientConfig: { Provider: 'openai', Model: 'gpt-realtime', EphemeralToken: 'ek_abc', ExpiresAt: '2026-01-01T00:00:00Z', SessionConfig: {} },
|
|
3128
|
+
});
|
|
3129
|
+
await resolver.StartRealtimeClientSession('target-1', makeCtx());
|
|
3130
|
+
return prepareClientSessionMock.mock.calls[0][0] as { ExcludeDirectActions?: boolean };
|
|
3131
|
+
}
|
|
3132
|
+
|
|
3133
|
+
it('prepares a scope-limited caller\'s session with no direct actions', async () => {
|
|
3134
|
+
const prepInput = await startAndCapturePrepInput(makeAnonResolver(), 'anon-1');
|
|
3135
|
+
|
|
3136
|
+
expect(prepInput.ExcludeDirectActions).toBe(true);
|
|
3137
|
+
});
|
|
3138
|
+
|
|
3139
|
+
it('prepares a caller that is not scope-limited with direct actions', async () => {
|
|
3140
|
+
const prepInput = await startAndCapturePrepInput(makeResolver(), 'user-1');
|
|
3141
|
+
|
|
3142
|
+
expect(prepInput.ExcludeDirectActions).toBe(false);
|
|
3143
|
+
});
|
|
3144
|
+
|
|
3083
3145
|
it('junction-links delegated artifacts under the SYSTEM user and stamps the hidden anchor with the SESSION owner', async () => {
|
|
3084
3146
|
const session = makeSessionEntity({ UserID: 'anon-1' });
|
|
3085
3147
|
const junctions: FakeSession[] = [];
|
|
@@ -3220,15 +3282,16 @@ describe('RealtimeClientSessionResolver — scoped-anonymous elevation (issue #3
|
|
|
3220
3282
|
function makeToolTurnProvider(detail: FakeSession): unknown {
|
|
3221
3283
|
const session = makeSessionEntity({
|
|
3222
3284
|
UserID: 'anon-1',
|
|
3223
|
-
Config_: JSON.stringify({ targetAgentID: 'target-1', promptRunID:
|
|
3285
|
+
Config_: JSON.stringify({ targetAgentID: 'target-1', coAgentRunID: CO_RUN_ID, promptRunID: PROMPT_RUN_ID }),
|
|
3224
3286
|
});
|
|
3225
|
-
const promptRun = makeSessionEntity({ ID:
|
|
3287
|
+
const promptRun = makeSessionEntity({ ID: PROMPT_RUN_ID, Messages: null });
|
|
3226
3288
|
return {
|
|
3227
3289
|
GetEntityObject: vi.fn(async (name: string) => {
|
|
3228
3290
|
if (name === 'MJ: AI Prompt Runs') return promptRun;
|
|
3229
3291
|
if (name === 'MJ: Conversation Details') return detail;
|
|
3230
3292
|
return session;
|
|
3231
3293
|
}),
|
|
3294
|
+
...sessionRunLookups([CO_RUN_ID], PROMPT_RUN_ID),
|
|
3232
3295
|
};
|
|
3233
3296
|
}
|
|
3234
3297
|
|
|
@@ -3388,7 +3451,8 @@ describe('RealtimeClientSessionResolver — colleague authorization (allowedAgen
|
|
|
3388
3451
|
|
|
3389
3452
|
it('excludes every colleague when the caller can run none of them', async () => {
|
|
3390
3453
|
currentProvider = makeProvider(() => makeMultiTargetSession('user-1'));
|
|
3391
|
-
|
|
3454
|
+
// The caller can run the lead target, and none of the colleagues.
|
|
3455
|
+
hasPermissionMock.mockImplementation((...args: unknown[]) => Promise.resolve(args[0] === 'target-1'));
|
|
3392
3456
|
|
|
3393
3457
|
await makeResolver().ExecuteRealtimeSessionTool(
|
|
3394
3458
|
'session-1', 'call-1', 'invoke-target-agent', '{}', makeCtx(), makePubSub(),
|
|
@@ -3397,7 +3461,7 @@ describe('RealtimeClientSessionResolver — colleague authorization (allowedAgen
|
|
|
3397
3461
|
expect(dispatchedAgentIDs()).toEqual([]);
|
|
3398
3462
|
});
|
|
3399
3463
|
|
|
3400
|
-
it('passes a single-target session through with
|
|
3464
|
+
it('passes a single-target session through with only the target permission check', async () => {
|
|
3401
3465
|
currentProvider = makeProvider(() => makeSessionEntity());
|
|
3402
3466
|
hasPermissionMock.mockResolvedValue(true);
|
|
3403
3467
|
|
|
@@ -3407,6 +3471,7 @@ describe('RealtimeClientSessionResolver — colleague authorization (allowedAgen
|
|
|
3407
3471
|
|
|
3408
3472
|
const input = executeRelayedToolMock.mock.calls[0][0] as { AllowedAgents?: unknown };
|
|
3409
3473
|
expect(input.AllowedAgents).toBeUndefined();
|
|
3410
|
-
expect(hasPermissionMock).
|
|
3474
|
+
expect(hasPermissionMock).toHaveBeenCalledTimes(1);
|
|
3475
|
+
expect((hasPermissionMock.mock.calls[0] as unknown[])[0]).toBe('target-1');
|
|
3411
3476
|
});
|
|
3412
3477
|
});
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ExecuteRemoteBrowserGoal` attaches a "Browser goal" step to the realtime co-agent run named by the
|
|
3
|
+
* session's `coAgentRunID`. The session owner can edit `Config`, so the run must be a record of the
|
|
4
|
+
* session before a step is attached to it.
|
|
5
|
+
*/
|
|
6
|
+
// type-graphql decorators on the resolver need the reflect-metadata polyfill loaded first.
|
|
7
|
+
import 'reflect-metadata';
|
|
8
|
+
|
|
9
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
10
|
+
|
|
11
|
+
// As in RemoteBrowserActionRecovery.test.ts: the decorators become no-ops so the resolver's plain logic runs.
|
|
12
|
+
vi.mock('type-graphql', () => {
|
|
13
|
+
const noopDecorator = () => () => undefined;
|
|
14
|
+
return {
|
|
15
|
+
Resolver: noopDecorator,
|
|
16
|
+
Mutation: noopDecorator,
|
|
17
|
+
Query: noopDecorator,
|
|
18
|
+
Subscription: noopDecorator,
|
|
19
|
+
ObjectType: noopDecorator,
|
|
20
|
+
InputType: noopDecorator,
|
|
21
|
+
Field: noopDecorator,
|
|
22
|
+
Arg: noopDecorator,
|
|
23
|
+
Args: noopDecorator,
|
|
24
|
+
Ctx: noopDecorator,
|
|
25
|
+
PubSub: noopDecorator,
|
|
26
|
+
Root: noopDecorator,
|
|
27
|
+
Float: class {},
|
|
28
|
+
Int: class {},
|
|
29
|
+
ID: class {},
|
|
30
|
+
};
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
const achieveGoalMock = vi.fn(async (_sessionID: string, _goal: string, _options: Record<string, unknown>) => ({ Success: true, Status: 'Done' }));
|
|
34
|
+
vi.mock('@memberjunction/remote-browser-server', () => ({
|
|
35
|
+
NormalizeInstanceKey: (key?: string) => key,
|
|
36
|
+
RemoteBrowserEngine: {
|
|
37
|
+
Instance: {
|
|
38
|
+
AchieveGoal: (sessionID: string, goal: string, options: Record<string, unknown>) => achieveGoalMock(sessionID, goal, options),
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
}));
|
|
42
|
+
|
|
43
|
+
const beginStepMock = vi.fn(async (_provider: unknown, _user: unknown, _coAgentRunID: string | undefined, _goal: string) => null);
|
|
44
|
+
vi.mock('../agentSessions/remoteBrowserGoalEngine.js', async (importOriginal) => ({
|
|
45
|
+
...(await importOriginal<typeof import('../agentSessions/remoteBrowserGoalEngine.js')>()),
|
|
46
|
+
beginBrowserGoalStep: (provider: unknown, user: unknown, coAgentRunID: string | undefined, goal: string) =>
|
|
47
|
+
beginStepMock(provider, user, coAgentRunID, goal),
|
|
48
|
+
finalizeBrowserGoalStep: vi.fn(async () => undefined),
|
|
49
|
+
}));
|
|
50
|
+
|
|
51
|
+
vi.mock('@memberjunction/aiengine', () => ({ AIEngine: { Instance: { Config: vi.fn(), Prompts: [] } } }));
|
|
52
|
+
vi.mock('@memberjunction/ai-prompts', async (importOriginal) => ({
|
|
53
|
+
...(await importOriginal<typeof import('@memberjunction/ai-prompts')>()),
|
|
54
|
+
AIPromptRunner: class {},
|
|
55
|
+
}));
|
|
56
|
+
vi.mock('@memberjunction/ai-core-plus', async (importOriginal) => ({
|
|
57
|
+
...(await importOriginal<typeof import('@memberjunction/ai-core-plus')>()),
|
|
58
|
+
AIPromptParams: class {},
|
|
59
|
+
}));
|
|
60
|
+
|
|
61
|
+
import { RemoteBrowserActionResolver } from '../resolvers/RemoteBrowserActionResolver.js';
|
|
62
|
+
import type { AppContext } from '../types.js';
|
|
63
|
+
import type { IMetadataProvider, UserInfo } from '@memberjunction/core';
|
|
64
|
+
import type { MJAIAgentSessionEntity } from '@memberjunction/core-entities';
|
|
65
|
+
|
|
66
|
+
const SESSION_ID = 'c3c3c3c3-2000-4000-8000-000000000001';
|
|
67
|
+
const CO_RUN_ID = 'c3c3c3c3-2000-4000-8000-000000000002';
|
|
68
|
+
/** A run that exists, but belongs to someone else's session. */
|
|
69
|
+
const FOREIGN_RUN_ID = 'c3c3c3c3-2000-4000-8000-0000000000f1';
|
|
70
|
+
|
|
71
|
+
/** The runs the fake lookup reports as records of the session. */
|
|
72
|
+
let sessionRunIDs: string[] = [];
|
|
73
|
+
const runViewsMock = vi.fn(async (paramsList: Array<{ EntityName?: string }>) =>
|
|
74
|
+
paramsList.map((params) => ({
|
|
75
|
+
Success: true,
|
|
76
|
+
Results: params.EntityName === 'MJ: AI Agent Runs' ? sessionRunIDs.map((ID) => ({ ID })) : [],
|
|
77
|
+
})),
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
/** Bypasses the ownership/provider plumbing (covered elsewhere); the session carries `ConfigJson`. */
|
|
81
|
+
class TestableResolver extends RemoteBrowserActionResolver {
|
|
82
|
+
public ConfigJson = '';
|
|
83
|
+
protected override requireUserAndProvider(): { contextUser: UserInfo; provider: IMetadataProvider } {
|
|
84
|
+
return {
|
|
85
|
+
contextUser: { ID: 'c3c3c3c3-2000-4000-8000-0000000000aa' } as unknown as UserInfo,
|
|
86
|
+
provider: { RunViews: runViewsMock } as unknown as IMetadataProvider,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
protected override async loadOwnedSession(): Promise<MJAIAgentSessionEntity> {
|
|
90
|
+
return { ID: SESSION_ID, AgentID: 'agent-1', Config_: this.ConfigJson } as unknown as MJAIAgentSessionEntity;
|
|
91
|
+
}
|
|
92
|
+
protected override async resolveProviderName(): Promise<string | undefined> {
|
|
93
|
+
return 'Self-Hosted Chrome';
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const ctx = { userPayload: { sessionId: 'push-sess-1' }, providers: [] } as unknown as AppContext;
|
|
98
|
+
|
|
99
|
+
async function startGoal(config: Record<string, unknown>): Promise<void> {
|
|
100
|
+
const resolver = new TestableResolver();
|
|
101
|
+
resolver.ConfigJson = JSON.stringify(config);
|
|
102
|
+
await resolver.ExecuteRemoteBrowserGoal(SESSION_ID, 'open the docs', ctx);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
beforeEach(() => {
|
|
106
|
+
sessionRunIDs = [];
|
|
107
|
+
runViewsMock.mockClear();
|
|
108
|
+
beginStepMock.mockClear();
|
|
109
|
+
achieveGoalMock.mockClear();
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
describe('RemoteBrowserActionResolver.ExecuteRemoteBrowserGoal — co-agent run from Config', () => {
|
|
113
|
+
it('does not attach the goal to a run that is not a record of the session', async () => {
|
|
114
|
+
await startGoal({ targetAgentID: 'target-1', coAgentRunID: FOREIGN_RUN_ID });
|
|
115
|
+
|
|
116
|
+
expect(beginStepMock).toHaveBeenCalledTimes(1);
|
|
117
|
+
expect(beginStepMock.mock.calls[0][2]).toBeUndefined();
|
|
118
|
+
expect(achieveGoalMock.mock.calls[0][2].AgentRunID).toBeUndefined();
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it('attaches the goal to the session\'s co-agent run', async () => {
|
|
122
|
+
sessionRunIDs = [CO_RUN_ID];
|
|
123
|
+
|
|
124
|
+
await startGoal({ targetAgentID: 'target-1', coAgentRunID: CO_RUN_ID });
|
|
125
|
+
|
|
126
|
+
expect(beginStepMock.mock.calls[0][2]).toBe(CO_RUN_ID);
|
|
127
|
+
expect(achieveGoalMock.mock.calls[0][2].AgentRunID).toBe(CO_RUN_ID);
|
|
128
|
+
});
|
|
129
|
+
});
|