@elevasis/core 0.1.0 → 0.2.1
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.js +195 -3
- package/dist/organization-model/index.js +195 -3
- package/package.json +1 -1
- package/src/README.md +24 -17
- package/src/__tests__/template-foundations-compatibility.test.ts +95 -14
- package/src/auth/multi-tenancy/types.ts +2 -1
- package/src/execution/engine/__tests__/fixtures/test-agents.ts +4 -4
- package/src/execution/engine/index.ts +5 -19
- package/src/execution/engine/tools/platform/index.ts +9 -33
- package/src/execution/engine/tools/registry.ts +109 -2
- package/src/execution/engine/tools/tool-maps.ts +88 -0
- package/src/organization-model/README.md +19 -4
- package/src/organization-model/__tests__/graph.test.ts +612 -0
- package/src/organization-model/__tests__/resolve.test.ts +208 -0
- package/src/organization-model/defaults.ts +1 -1
- package/src/organization-model/organization-graph.mdx +262 -0
- package/src/organization-model/organization-model.mdx +257 -0
- package/src/organization-model/resolve.ts +26 -2
- package/src/organization-model/schema.ts +203 -1
- package/src/platform/constants/versions.ts +1 -1
- package/src/platform/registry/__tests__/resource-registry.integration.test.ts +24 -0
- package/src/platform/registry/__tests__/resource-registry.test.ts +63 -0
- package/src/platform/registry/resource-registry.ts +98 -10
- package/src/projects/api-schemas.ts +2 -1
- package/src/reference/_generated/contracts.md +1044 -0
- package/src/reference/glossary.md +88 -0
- package/src/server.ts +2 -3
- package/src/execution/engine/tools/platform/resource-invocation/__tests__/edge-cases.test.ts +0 -507
- package/src/execution/engine/tools/platform/resource-invocation/__tests__/resource-invocation-service.test.ts +0 -500
- package/src/execution/engine/tools/platform/resource-invocation/__tests__/tool.test.ts +0 -555
- package/src/execution/engine/tools/platform/resource-invocation/dynamic-tool.ts +0 -94
- package/src/execution/engine/tools/platform/resource-invocation/index.ts +0 -14
- package/src/execution/engine/tools/platform/resource-invocation/resource-invocation-service.ts +0 -147
- package/src/execution/engine/tools/platform/resource-invocation/tool.ts +0 -115
- package/src/execution/engine/tools/platform/resource-invocation/types.ts +0 -31
|
@@ -1,500 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
|
2
|
-
import { z } from 'zod'
|
|
3
|
-
import { ResourceInvocationService, createResourceInvocationService } from '../resource-invocation-service'
|
|
4
|
-
import type { ResourceRegistry } from '../../../../../../platform/registry/resource-registry'
|
|
5
|
-
import type { WorkflowDefinition } from '../../../../workflow/types'
|
|
6
|
-
import type { AgentDefinition } from '../../../../agent/core/types'
|
|
7
|
-
import type { ResourceInvocationResult, ExecuteResourceCallback } from '../types'
|
|
8
|
-
import { createMockExecutionContext } from '../../../../test-utils/mocks'
|
|
9
|
-
|
|
10
|
-
describe('ResourceInvocationService', () => {
|
|
11
|
-
// Mock data
|
|
12
|
-
const mockContext = createMockExecutionContext({
|
|
13
|
-
organizationId: 'org-123',
|
|
14
|
-
organizationName: 'test-org',
|
|
15
|
-
executionId: 'exec-456',
|
|
16
|
-
resourceId: 'parent-agent',
|
|
17
|
-
executionDepth: 0
|
|
18
|
-
})
|
|
19
|
-
|
|
20
|
-
const mockWorkflowDefinition: WorkflowDefinition = {
|
|
21
|
-
config: {
|
|
22
|
-
resourceId: 'validation-workflow',
|
|
23
|
-
name: 'Validation Workflow',
|
|
24
|
-
description: 'Validates data',
|
|
25
|
-
version: '1.0.0',
|
|
26
|
-
type: 'workflow',
|
|
27
|
-
status: 'dev'
|
|
28
|
-
},
|
|
29
|
-
contract: {
|
|
30
|
-
inputSchema: z.object({
|
|
31
|
-
email: z.string().email(),
|
|
32
|
-
name: z.string()
|
|
33
|
-
}),
|
|
34
|
-
outputSchema: z.object({
|
|
35
|
-
valid: z.boolean(),
|
|
36
|
-
errors: z.array(z.string())
|
|
37
|
-
})
|
|
38
|
-
},
|
|
39
|
-
entryPoint: 'validate',
|
|
40
|
-
steps: {}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const mockAgentDefinition: AgentDefinition = {
|
|
44
|
-
config: {
|
|
45
|
-
resourceId: 'research-agent',
|
|
46
|
-
name: 'Research Agent',
|
|
47
|
-
description: 'Researches topics',
|
|
48
|
-
version: '1.0.0',
|
|
49
|
-
type: 'agent',
|
|
50
|
-
status: 'dev'
|
|
51
|
-
},
|
|
52
|
-
contract: {
|
|
53
|
-
inputSchema: z.object({
|
|
54
|
-
query: z.string()
|
|
55
|
-
}),
|
|
56
|
-
outputSchema: z.object({
|
|
57
|
-
results: z.string()
|
|
58
|
-
})
|
|
59
|
-
},
|
|
60
|
-
modelConfig: {
|
|
61
|
-
provider: 'openai',
|
|
62
|
-
model: 'gpt-4o',
|
|
63
|
-
temperature: 0.7
|
|
64
|
-
},
|
|
65
|
-
systemPrompt: 'You are a research assistant',
|
|
66
|
-
tools: []
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
let mockRegistry: ResourceRegistry
|
|
70
|
-
let mockExecuteResource: ReturnType<typeof vi.fn>
|
|
71
|
-
let service: ResourceInvocationService
|
|
72
|
-
|
|
73
|
-
beforeEach(() => {
|
|
74
|
-
// Create mock registry
|
|
75
|
-
mockRegistry = {
|
|
76
|
-
getResourceDefinition: vi.fn(),
|
|
77
|
-
getRelationships: vi.fn().mockReturnValue(undefined)
|
|
78
|
-
} as unknown as ResourceRegistry
|
|
79
|
-
|
|
80
|
-
// Create mock execute function
|
|
81
|
-
mockExecuteResource = vi.fn()
|
|
82
|
-
|
|
83
|
-
// Create service instance
|
|
84
|
-
service = new ResourceInvocationService(mockRegistry, mockExecuteResource)
|
|
85
|
-
})
|
|
86
|
-
|
|
87
|
-
describe('executeSync', () => {
|
|
88
|
-
it('validates resource exists', async () => {
|
|
89
|
-
// Setup: Mock registry returns undefined for resourceId
|
|
90
|
-
vi.mocked(mockRegistry.getResourceDefinition).mockReturnValue(null)
|
|
91
|
-
|
|
92
|
-
const result = await service.executeSync(
|
|
93
|
-
'non-existent-resource',
|
|
94
|
-
{ email: 'test@test.com', name: 'Test' },
|
|
95
|
-
'test-org',
|
|
96
|
-
mockContext
|
|
97
|
-
)
|
|
98
|
-
|
|
99
|
-
expect(result.success).toBe(false)
|
|
100
|
-
expect(result.error).toContain('not found')
|
|
101
|
-
expect(result.error).toContain('non-existent-resource')
|
|
102
|
-
expect(mockRegistry.getResourceDefinition).toHaveBeenCalledWith('test-org', 'non-existent-resource')
|
|
103
|
-
})
|
|
104
|
-
|
|
105
|
-
it('invokes workflow and returns result', async () => {
|
|
106
|
-
// Setup: Mock registry returns workflow definition
|
|
107
|
-
vi.mocked(mockRegistry.getResourceDefinition).mockReturnValue(mockWorkflowDefinition)
|
|
108
|
-
|
|
109
|
-
// Mock successful execution
|
|
110
|
-
const mockResult: ResourceInvocationResult = {
|
|
111
|
-
success: true,
|
|
112
|
-
output: { valid: true, errors: [] },
|
|
113
|
-
executionId: 'exec-789',
|
|
114
|
-
resourceType: 'workflow'
|
|
115
|
-
}
|
|
116
|
-
mockExecuteResource.mockResolvedValue(mockResult)
|
|
117
|
-
|
|
118
|
-
const result = await service.executeSync(
|
|
119
|
-
'validation-workflow',
|
|
120
|
-
{ email: 'test@test.com', name: 'Test User' },
|
|
121
|
-
'test-org',
|
|
122
|
-
mockContext
|
|
123
|
-
)
|
|
124
|
-
|
|
125
|
-
expect(result.success).toBe(true)
|
|
126
|
-
expect(result.resourceType).toBe('workflow')
|
|
127
|
-
expect(result.output).toEqual({ valid: true, errors: [] })
|
|
128
|
-
expect(result.executionId).toBe('exec-789')
|
|
129
|
-
|
|
130
|
-
// Verify executeResource called with correct parameters
|
|
131
|
-
expect(mockExecuteResource).toHaveBeenCalledWith(
|
|
132
|
-
{
|
|
133
|
-
resourceId: 'validation-workflow',
|
|
134
|
-
input: { email: 'test@test.com', name: 'Test User' },
|
|
135
|
-
organizationId: 'org-123',
|
|
136
|
-
organizationName: 'test-org'
|
|
137
|
-
},
|
|
138
|
-
mockContext
|
|
139
|
-
)
|
|
140
|
-
})
|
|
141
|
-
|
|
142
|
-
it('invokes agent and returns result', async () => {
|
|
143
|
-
// Setup: Mock registry returns agent definition
|
|
144
|
-
vi.mocked(mockRegistry.getResourceDefinition).mockReturnValue(mockAgentDefinition)
|
|
145
|
-
|
|
146
|
-
// Mock successful execution
|
|
147
|
-
const mockResult: ResourceInvocationResult = {
|
|
148
|
-
success: true,
|
|
149
|
-
output: { results: 'Research findings...' },
|
|
150
|
-
executionId: 'exec-999',
|
|
151
|
-
resourceType: 'agent'
|
|
152
|
-
}
|
|
153
|
-
mockExecuteResource.mockResolvedValue(mockResult)
|
|
154
|
-
|
|
155
|
-
const result = await service.executeSync(
|
|
156
|
-
'research-agent',
|
|
157
|
-
{ query: 'AI trends' },
|
|
158
|
-
'test-org',
|
|
159
|
-
mockContext
|
|
160
|
-
)
|
|
161
|
-
|
|
162
|
-
expect(result.success).toBe(true)
|
|
163
|
-
expect(result.resourceType).toBe('agent')
|
|
164
|
-
expect(result.output).toEqual({ results: 'Research findings...' })
|
|
165
|
-
expect(result.executionId).toBe('exec-999')
|
|
166
|
-
})
|
|
167
|
-
|
|
168
|
-
it('validates input against resource contract', async () => {
|
|
169
|
-
// Setup: Mock registry returns workflow with Zod schema
|
|
170
|
-
vi.mocked(mockRegistry.getResourceDefinition).mockReturnValue(mockWorkflowDefinition)
|
|
171
|
-
|
|
172
|
-
// Invalid input (missing required fields)
|
|
173
|
-
const result = await service.executeSync(
|
|
174
|
-
'validation-workflow',
|
|
175
|
-
{ email: 'invalid-email' }, // Missing 'name', invalid email
|
|
176
|
-
'test-org',
|
|
177
|
-
mockContext
|
|
178
|
-
)
|
|
179
|
-
|
|
180
|
-
expect(result.success).toBe(false)
|
|
181
|
-
expect(result.error).toContain('Input validation failed')
|
|
182
|
-
expect(mockExecuteResource).not.toHaveBeenCalled()
|
|
183
|
-
})
|
|
184
|
-
|
|
185
|
-
it('passes parent context to nested execution', async () => {
|
|
186
|
-
// Setup: Mock registry returns workflow
|
|
187
|
-
vi.mocked(mockRegistry.getResourceDefinition).mockReturnValue(mockWorkflowDefinition)
|
|
188
|
-
|
|
189
|
-
// Mock executor that captures context
|
|
190
|
-
const capturedContext = vi.fn()
|
|
191
|
-
mockExecuteResource.mockImplementation(async (request, context) => {
|
|
192
|
-
capturedContext(context)
|
|
193
|
-
return {
|
|
194
|
-
success: true,
|
|
195
|
-
output: { valid: true, errors: [] },
|
|
196
|
-
executionId: 'exec-nested',
|
|
197
|
-
resourceType: 'workflow'
|
|
198
|
-
}
|
|
199
|
-
})
|
|
200
|
-
|
|
201
|
-
await service.executeSync(
|
|
202
|
-
'validation-workflow',
|
|
203
|
-
{ email: 'test@test.com', name: 'Test' },
|
|
204
|
-
'test-org',
|
|
205
|
-
mockContext
|
|
206
|
-
)
|
|
207
|
-
|
|
208
|
-
// Verify parent context was passed
|
|
209
|
-
expect(capturedContext).toHaveBeenCalledWith(mockContext)
|
|
210
|
-
})
|
|
211
|
-
|
|
212
|
-
it('handles execution errors from executor', async () => {
|
|
213
|
-
// Setup: Mock registry returns workflow
|
|
214
|
-
vi.mocked(mockRegistry.getResourceDefinition).mockReturnValue(mockWorkflowDefinition)
|
|
215
|
-
|
|
216
|
-
// Mock failed execution
|
|
217
|
-
const mockResult: ResourceInvocationResult = {
|
|
218
|
-
success: false,
|
|
219
|
-
output: null,
|
|
220
|
-
executionId: 'exec-fail',
|
|
221
|
-
resourceType: 'workflow',
|
|
222
|
-
error: 'Execution timeout'
|
|
223
|
-
}
|
|
224
|
-
mockExecuteResource.mockResolvedValue(mockResult)
|
|
225
|
-
|
|
226
|
-
const result = await service.executeSync(
|
|
227
|
-
'validation-workflow',
|
|
228
|
-
{ email: 'test@test.com', name: 'Test' },
|
|
229
|
-
'test-org',
|
|
230
|
-
mockContext
|
|
231
|
-
)
|
|
232
|
-
|
|
233
|
-
expect(result.success).toBe(false)
|
|
234
|
-
expect(result.error).toBe('Execution timeout')
|
|
235
|
-
expect(result.resourceType).toBe('workflow')
|
|
236
|
-
})
|
|
237
|
-
|
|
238
|
-
it('preserves organization context through invocation', async () => {
|
|
239
|
-
// Setup: Mock registry returns workflow
|
|
240
|
-
vi.mocked(mockRegistry.getResourceDefinition).mockReturnValue(mockWorkflowDefinition)
|
|
241
|
-
|
|
242
|
-
mockExecuteResource.mockResolvedValue({
|
|
243
|
-
success: true,
|
|
244
|
-
output: { valid: true, errors: [] },
|
|
245
|
-
executionId: 'exec-org',
|
|
246
|
-
resourceType: 'workflow'
|
|
247
|
-
})
|
|
248
|
-
|
|
249
|
-
await service.executeSync(
|
|
250
|
-
'validation-workflow',
|
|
251
|
-
{ email: 'test@test.com', name: 'Test' },
|
|
252
|
-
'test-org',
|
|
253
|
-
mockContext
|
|
254
|
-
)
|
|
255
|
-
|
|
256
|
-
// Verify organizationId and organizationName passed correctly
|
|
257
|
-
expect(mockExecuteResource).toHaveBeenCalledWith(
|
|
258
|
-
expect.objectContaining({
|
|
259
|
-
organizationId: 'org-123',
|
|
260
|
-
organizationName: 'test-org'
|
|
261
|
-
}),
|
|
262
|
-
mockContext
|
|
263
|
-
)
|
|
264
|
-
})
|
|
265
|
-
|
|
266
|
-
it('handles workflow with null outputSchema', async () => {
|
|
267
|
-
// Create workflow with no outputSchema (fire-and-forget)
|
|
268
|
-
const fireAndForgetWorkflow: WorkflowDefinition = {
|
|
269
|
-
...mockWorkflowDefinition,
|
|
270
|
-
contract: {
|
|
271
|
-
inputSchema: z.object({ data: z.string() }),
|
|
272
|
-
outputSchema: null
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
vi.mocked(mockRegistry.getResourceDefinition).mockReturnValue(fireAndForgetWorkflow)
|
|
277
|
-
|
|
278
|
-
mockExecuteResource.mockResolvedValue({
|
|
279
|
-
success: true,
|
|
280
|
-
output: null,
|
|
281
|
-
executionId: 'exec-fire',
|
|
282
|
-
resourceType: 'workflow'
|
|
283
|
-
})
|
|
284
|
-
|
|
285
|
-
const result = await service.executeSync(
|
|
286
|
-
'fire-and-forget-workflow',
|
|
287
|
-
{ data: 'test' },
|
|
288
|
-
'test-org',
|
|
289
|
-
mockContext
|
|
290
|
-
)
|
|
291
|
-
|
|
292
|
-
expect(result.success).toBe(true)
|
|
293
|
-
expect(result.output).toBeNull()
|
|
294
|
-
})
|
|
295
|
-
})
|
|
296
|
-
|
|
297
|
-
describe('createResourceInvocationService', () => {
|
|
298
|
-
it('creates service with valid dependencies', () => {
|
|
299
|
-
const service = createResourceInvocationService(mockRegistry, mockExecuteResource)
|
|
300
|
-
|
|
301
|
-
expect(service).toBeInstanceOf(ResourceInvocationService)
|
|
302
|
-
})
|
|
303
|
-
|
|
304
|
-
it('throws if registry not provided', () => {
|
|
305
|
-
expect(() => {
|
|
306
|
-
createResourceInvocationService(null as unknown as ResourceRegistry, mockExecuteResource)
|
|
307
|
-
}).toThrow('ResourceRegistry required')
|
|
308
|
-
})
|
|
309
|
-
|
|
310
|
-
it('throws if executeResource callback not provided', () => {
|
|
311
|
-
expect(() => {
|
|
312
|
-
createResourceInvocationService(mockRegistry, null as unknown as ExecuteResourceCallback)
|
|
313
|
-
}).toThrow('executeResource callback required')
|
|
314
|
-
})
|
|
315
|
-
})
|
|
316
|
-
|
|
317
|
-
describe('multi-tenancy safety', () => {
|
|
318
|
-
it('scopes resource lookup by organization name', async () => {
|
|
319
|
-
vi.mocked(mockRegistry.getResourceDefinition).mockReturnValue(mockWorkflowDefinition)
|
|
320
|
-
|
|
321
|
-
mockExecuteResource.mockResolvedValue({
|
|
322
|
-
success: true,
|
|
323
|
-
output: { valid: true, errors: [] },
|
|
324
|
-
executionId: 'exec-tenant',
|
|
325
|
-
resourceType: 'workflow'
|
|
326
|
-
})
|
|
327
|
-
|
|
328
|
-
await service.executeSync(
|
|
329
|
-
'validation-workflow',
|
|
330
|
-
{ email: 'test@test.com', name: 'Test' },
|
|
331
|
-
'acme-corp',
|
|
332
|
-
mockContext
|
|
333
|
-
)
|
|
334
|
-
|
|
335
|
-
// Verify registry called with correct organization name
|
|
336
|
-
expect(mockRegistry.getResourceDefinition).toHaveBeenCalledWith('acme-corp', 'validation-workflow')
|
|
337
|
-
})
|
|
338
|
-
|
|
339
|
-
it('passes organization context to nested execution', async () => {
|
|
340
|
-
vi.mocked(mockRegistry.getResourceDefinition).mockReturnValue(mockWorkflowDefinition)
|
|
341
|
-
|
|
342
|
-
const contextWithOrg = createMockExecutionContext({
|
|
343
|
-
organizationId: 'org-different',
|
|
344
|
-
organizationName: 'different-org'
|
|
345
|
-
})
|
|
346
|
-
|
|
347
|
-
mockExecuteResource.mockResolvedValue({
|
|
348
|
-
success: true,
|
|
349
|
-
output: { valid: true, errors: [] },
|
|
350
|
-
executionId: 'exec-ctx',
|
|
351
|
-
resourceType: 'workflow'
|
|
352
|
-
})
|
|
353
|
-
|
|
354
|
-
await service.executeSync(
|
|
355
|
-
'validation-workflow',
|
|
356
|
-
{ email: 'test@test.com', name: 'Test' },
|
|
357
|
-
'different-org',
|
|
358
|
-
contextWithOrg
|
|
359
|
-
)
|
|
360
|
-
|
|
361
|
-
// Verify correct organization context passed
|
|
362
|
-
expect(mockExecuteResource).toHaveBeenCalledWith(
|
|
363
|
-
expect.objectContaining({
|
|
364
|
-
organizationId: 'org-different',
|
|
365
|
-
organizationName: 'different-org'
|
|
366
|
-
}),
|
|
367
|
-
contextWithOrg
|
|
368
|
-
)
|
|
369
|
-
})
|
|
370
|
-
})
|
|
371
|
-
|
|
372
|
-
describe('relationship enforcement', () => {
|
|
373
|
-
it('allows invocation when relationship is declared (workflow target)', async () => {
|
|
374
|
-
vi.mocked(mockRegistry.getResourceDefinition).mockReturnValue(mockWorkflowDefinition)
|
|
375
|
-
vi.mocked(mockRegistry.getRelationships).mockReturnValue({
|
|
376
|
-
'parent-agent': {
|
|
377
|
-
triggers: { workflows: ['validation-workflow'] }
|
|
378
|
-
}
|
|
379
|
-
})
|
|
380
|
-
|
|
381
|
-
mockExecuteResource.mockResolvedValue({
|
|
382
|
-
success: true,
|
|
383
|
-
output: { valid: true, errors: [] },
|
|
384
|
-
executionId: 'exec-rel',
|
|
385
|
-
resourceType: 'workflow'
|
|
386
|
-
})
|
|
387
|
-
|
|
388
|
-
const result = await service.executeSync(
|
|
389
|
-
'validation-workflow',
|
|
390
|
-
{ email: 'test@test.com', name: 'Test' },
|
|
391
|
-
'test-org',
|
|
392
|
-
mockContext
|
|
393
|
-
)
|
|
394
|
-
|
|
395
|
-
expect(result.success).toBe(true)
|
|
396
|
-
})
|
|
397
|
-
|
|
398
|
-
it('allows invocation when relationship is declared (agent target)', async () => {
|
|
399
|
-
vi.mocked(mockRegistry.getResourceDefinition).mockReturnValue(mockAgentDefinition)
|
|
400
|
-
vi.mocked(mockRegistry.getRelationships).mockReturnValue({
|
|
401
|
-
'parent-agent': {
|
|
402
|
-
triggers: { agents: ['research-agent'] }
|
|
403
|
-
}
|
|
404
|
-
})
|
|
405
|
-
|
|
406
|
-
mockExecuteResource.mockResolvedValue({
|
|
407
|
-
success: true,
|
|
408
|
-
output: { results: 'findings' },
|
|
409
|
-
executionId: 'exec-agent-rel',
|
|
410
|
-
resourceType: 'agent'
|
|
411
|
-
})
|
|
412
|
-
|
|
413
|
-
const result = await service.executeSync(
|
|
414
|
-
'research-agent',
|
|
415
|
-
{ query: 'test' },
|
|
416
|
-
'test-org',
|
|
417
|
-
mockContext
|
|
418
|
-
)
|
|
419
|
-
|
|
420
|
-
expect(result.success).toBe(true)
|
|
421
|
-
})
|
|
422
|
-
|
|
423
|
-
it('throws when invocation is not declared', async () => {
|
|
424
|
-
vi.mocked(mockRegistry.getResourceDefinition).mockReturnValue(mockWorkflowDefinition)
|
|
425
|
-
vi.mocked(mockRegistry.getRelationships).mockReturnValue({
|
|
426
|
-
'parent-agent': {
|
|
427
|
-
triggers: { workflows: ['other-workflow'] }
|
|
428
|
-
}
|
|
429
|
-
})
|
|
430
|
-
|
|
431
|
-
await expect(
|
|
432
|
-
service.executeSync(
|
|
433
|
-
'validation-workflow',
|
|
434
|
-
{ email: 'test@test.com', name: 'Test' },
|
|
435
|
-
'test-org',
|
|
436
|
-
mockContext
|
|
437
|
-
)
|
|
438
|
-
).rejects.toThrow('Undeclared resource invocation')
|
|
439
|
-
})
|
|
440
|
-
|
|
441
|
-
it('throws when caller has no entry in relationships', async () => {
|
|
442
|
-
vi.mocked(mockRegistry.getResourceDefinition).mockReturnValue(mockWorkflowDefinition)
|
|
443
|
-
vi.mocked(mockRegistry.getRelationships).mockReturnValue({
|
|
444
|
-
'some-other-resource': {
|
|
445
|
-
triggers: { workflows: ['validation-workflow'] }
|
|
446
|
-
}
|
|
447
|
-
})
|
|
448
|
-
|
|
449
|
-
await expect(
|
|
450
|
-
service.executeSync(
|
|
451
|
-
'validation-workflow',
|
|
452
|
-
{ email: 'test@test.com', name: 'Test' },
|
|
453
|
-
'test-org',
|
|
454
|
-
mockContext
|
|
455
|
-
)
|
|
456
|
-
).rejects.toThrow('Undeclared resource invocation')
|
|
457
|
-
})
|
|
458
|
-
|
|
459
|
-
it('skips enforcement when org has no relationships (undefined)', async () => {
|
|
460
|
-
vi.mocked(mockRegistry.getResourceDefinition).mockReturnValue(mockWorkflowDefinition)
|
|
461
|
-
vi.mocked(mockRegistry.getRelationships).mockReturnValue(undefined)
|
|
462
|
-
|
|
463
|
-
mockExecuteResource.mockResolvedValue({
|
|
464
|
-
success: true,
|
|
465
|
-
output: { valid: true, errors: [] },
|
|
466
|
-
executionId: 'exec-no-rel',
|
|
467
|
-
resourceType: 'workflow'
|
|
468
|
-
})
|
|
469
|
-
|
|
470
|
-
const result = await service.executeSync(
|
|
471
|
-
'validation-workflow',
|
|
472
|
-
{ email: 'test@test.com', name: 'Test' },
|
|
473
|
-
'test-org',
|
|
474
|
-
mockContext
|
|
475
|
-
)
|
|
476
|
-
|
|
477
|
-
expect(result.success).toBe(true)
|
|
478
|
-
})
|
|
479
|
-
|
|
480
|
-
it('error message includes actionable fix instructions', async () => {
|
|
481
|
-
vi.mocked(mockRegistry.getResourceDefinition).mockReturnValue(mockWorkflowDefinition)
|
|
482
|
-
vi.mocked(mockRegistry.getRelationships).mockReturnValue({
|
|
483
|
-
'parent-agent': {
|
|
484
|
-
triggers: { workflows: ['other-workflow'] }
|
|
485
|
-
}
|
|
486
|
-
})
|
|
487
|
-
|
|
488
|
-
await expect(
|
|
489
|
-
service.executeSync(
|
|
490
|
-
'validation-workflow',
|
|
491
|
-
{ email: 'test@test.com', name: 'Test' },
|
|
492
|
-
'test-org',
|
|
493
|
-
mockContext
|
|
494
|
-
)
|
|
495
|
-
).rejects.toThrow(
|
|
496
|
-
`Add to relationships: { 'parent-agent': { triggers: { workflows: ['validation-workflow'] } } }`
|
|
497
|
-
)
|
|
498
|
-
})
|
|
499
|
-
})
|
|
500
|
-
})
|