@stigmer/server 3.20.0 → 3.22.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/authorization/evaluator.d.ts +7 -1
- package/dist/authorization/evaluator.d.ts.map +1 -1
- package/dist/authorization/evaluator.js.map +1 -1
- package/dist/authorization/list-read-scope.d.ts.map +1 -1
- package/dist/authorization/list-read-scope.js +19 -11
- package/dist/authorization/list-read-scope.js.map +1 -1
- package/dist/authorization/model/organization.d.ts.map +1 -1
- package/dist/authorization/model/organization.js +2 -0
- package/dist/authorization/model/organization.js.map +1 -1
- package/dist/boot/compose.d.ts.map +1 -1
- package/dist/boot/compose.js +0 -1
- package/dist/boot/compose.js.map +1 -1
- package/dist/boot/inprocess.d.ts +0 -2
- package/dist/boot/inprocess.d.ts.map +1 -1
- package/dist/boot/inprocess.js +0 -6
- package/dist/boot/inprocess.js.map +1 -1
- package/dist/domain/agent/controller.d.ts +2 -2
- package/dist/domain/agent/controller.d.ts.map +1 -1
- package/dist/domain/agent/controller.js +3 -17
- package/dist/domain/agent/controller.js.map +1 -1
- package/dist/domain/agent/steps.d.ts +0 -1
- package/dist/domain/agent/steps.d.ts.map +1 -1
- package/dist/domain/agent/steps.js +1 -40
- package/dist/domain/agent/steps.js.map +1 -1
- package/dist/domain/agentchannel/controller.d.ts.map +1 -1
- package/dist/domain/agentchannel/controller.js +6 -1
- package/dist/domain/agentchannel/controller.js.map +1 -1
- package/dist/domain/agentchannel/steps.d.ts +19 -0
- package/dist/domain/agentchannel/steps.d.ts.map +1 -1
- package/dist/domain/agentchannel/steps.js +32 -0
- package/dist/domain/agentchannel/steps.js.map +1 -1
- package/dist/domain/agentexecution/controller.d.ts.map +1 -1
- package/dist/domain/agentexecution/controller.js +7 -9
- package/dist/domain/agentexecution/controller.js.map +1 -1
- package/dist/domain/agentexecution/create-execution-context-step.d.ts +0 -2
- package/dist/domain/agentexecution/create-execution-context-step.d.ts.map +1 -1
- package/dist/domain/agentexecution/create-execution-context-step.js +179 -60
- package/dist/domain/agentexecution/create-execution-context-step.js.map +1 -1
- package/dist/domain/agentexecution/create-steps.d.ts +16 -31
- package/dist/domain/agentexecution/create-steps.d.ts.map +1 -1
- package/dist/domain/agentexecution/create-steps.js +36 -102
- package/dist/domain/agentexecution/create-steps.js.map +1 -1
- package/dist/domain/agentexecution/run-target.d.ts +7 -3
- package/dist/domain/agentexecution/run-target.d.ts.map +1 -1
- package/dist/domain/agentexecution/run-target.js.map +1 -1
- package/dist/domain/agentinstance/controller.d.ts +5 -5
- package/dist/domain/agentinstance/controller.d.ts.map +1 -1
- package/dist/domain/agentinstance/controller.js +6 -1
- package/dist/domain/agentinstance/controller.js.map +1 -1
- package/dist/domain/agentinstance/steps.d.ts +43 -8
- package/dist/domain/agentinstance/steps.d.ts.map +1 -1
- package/dist/domain/agentinstance/steps.js +71 -8
- package/dist/domain/agentinstance/steps.js.map +1 -1
- package/dist/domain/agentshare/controller.d.ts.map +1 -1
- package/dist/domain/agentshare/controller.js +7 -1
- package/dist/domain/agentshare/controller.js.map +1 -1
- package/dist/domain/agentshare/steps.d.ts +58 -0
- package/dist/domain/agentshare/steps.d.ts.map +1 -1
- package/dist/domain/agentshare/steps.js +109 -4
- package/dist/domain/agentshare/steps.js.map +1 -1
- package/dist/domain/artifact/controller.js +21 -25
- package/dist/domain/artifact/controller.js.map +1 -1
- package/dist/domain/channelapp/controller.d.ts.map +1 -1
- package/dist/domain/channelapp/controller.js +2 -0
- package/dist/domain/channelapp/controller.js.map +1 -1
- package/dist/domain/environment/controller.d.ts.map +1 -1
- package/dist/domain/environment/controller.js +2 -0
- package/dist/domain/environment/controller.js.map +1 -1
- package/dist/domain/environment/personal.d.ts +42 -0
- package/dist/domain/environment/personal.d.ts.map +1 -0
- package/dist/domain/environment/personal.js +96 -0
- package/dist/domain/environment/personal.js.map +1 -0
- package/dist/domain/executioncontext/controller.d.ts.map +1 -1
- package/dist/domain/executioncontext/controller.js +2 -0
- package/dist/domain/executioncontext/controller.js.map +1 -1
- package/dist/domain/executioncontext/steps.d.ts.map +1 -1
- package/dist/domain/executioncontext/steps.js +2 -1
- package/dist/domain/executioncontext/steps.js.map +1 -1
- package/dist/domain/mcpserver/connect.d.ts +0 -2
- package/dist/domain/mcpserver/connect.d.ts.map +1 -1
- package/dist/domain/mcpserver/connect.js +24 -79
- package/dist/domain/mcpserver/connect.js.map +1 -1
- package/dist/domain/mcpserver/controller.d.ts.map +1 -1
- package/dist/domain/mcpserver/controller.js +2 -0
- package/dist/domain/mcpserver/controller.js.map +1 -1
- package/dist/domain/mcpserver/start-connect.d.ts.map +1 -1
- package/dist/domain/mcpserver/start-connect.js +8 -7
- package/dist/domain/mcpserver/start-connect.js.map +1 -1
- package/dist/domain/memory/controller.d.ts.map +1 -1
- package/dist/domain/memory/controller.js +6 -1
- package/dist/domain/memory/controller.js.map +1 -1
- package/dist/domain/memory/steps.d.ts +23 -0
- package/dist/domain/memory/steps.d.ts.map +1 -1
- package/dist/domain/memory/steps.js +35 -0
- package/dist/domain/memory/steps.js.map +1 -1
- package/dist/domain/oauthapp/controller.d.ts.map +1 -1
- package/dist/domain/oauthapp/controller.js +2 -0
- package/dist/domain/oauthapp/controller.js.map +1 -1
- package/dist/domain/plugin/controller.d.ts.map +1 -1
- package/dist/domain/plugin/controller.js +5 -24
- package/dist/domain/plugin/controller.js.map +1 -1
- package/dist/domain/plugin/overlay/sanitize.js +2 -2
- package/dist/domain/schedule/controller.d.ts.map +1 -1
- package/dist/domain/schedule/controller.js +7 -1
- package/dist/domain/schedule/controller.js.map +1 -1
- package/dist/domain/schedule/steps.d.ts +19 -0
- package/dist/domain/schedule/steps.d.ts.map +1 -1
- package/dist/domain/schedule/steps.js +32 -0
- package/dist/domain/schedule/steps.js.map +1 -1
- package/dist/domain/session/controller.d.ts +0 -7
- package/dist/domain/session/controller.d.ts.map +1 -1
- package/dist/domain/session/controller.js +11 -16
- package/dist/domain/session/controller.js.map +1 -1
- package/dist/domain/session/run-target.d.ts +9 -8
- package/dist/domain/session/run-target.d.ts.map +1 -1
- package/dist/domain/session/run-target.js.map +1 -1
- package/dist/domain/session/steps.d.ts +8 -36
- package/dist/domain/session/steps.d.ts.map +1 -1
- package/dist/domain/session/steps.js +27 -172
- package/dist/domain/session/steps.js.map +1 -1
- package/dist/domain/skill/controller.d.ts.map +1 -1
- package/dist/domain/skill/controller.js +8 -17
- package/dist/domain/skill/controller.js.map +1 -1
- package/dist/domain/workflow/controller.d.ts.map +1 -1
- package/dist/domain/workflow/controller.js +30 -107
- package/dist/domain/workflow/controller.js.map +1 -1
- package/dist/domain/workflow/version-resolution.d.ts +5 -0
- package/dist/domain/workflow/version-resolution.d.ts.map +1 -0
- package/dist/domain/workflow/version-resolution.js +113 -0
- package/dist/domain/workflow/version-resolution.js.map +1 -0
- package/dist/domain/workflowexecution/create-steps.d.ts +4 -3
- package/dist/domain/workflowexecution/create-steps.d.ts.map +1 -1
- package/dist/domain/workflowexecution/create-steps.js +4 -3
- package/dist/domain/workflowexecution/create-steps.js.map +1 -1
- package/dist/domain/workflowinstance/controller.d.ts.map +1 -1
- package/dist/domain/workflowinstance/controller.js +6 -1
- package/dist/domain/workflowinstance/controller.js.map +1 -1
- package/dist/domain/workflowinstance/steps.d.ts +20 -0
- package/dist/domain/workflowinstance/steps.d.ts.map +1 -1
- package/dist/domain/workflowinstance/steps.js +39 -0
- package/dist/domain/workflowinstance/steps.js.map +1 -1
- package/dist/extensions/identity.d.ts +19 -0
- package/dist/extensions/identity.d.ts.map +1 -1
- package/dist/extensions/identity.js +22 -3
- package/dist/extensions/identity.js.map +1 -1
- package/dist/extensions/list-read-scope.d.ts +41 -7
- package/dist/extensions/list-read-scope.d.ts.map +1 -1
- package/dist/extensions/list-read-scope.js +13 -2
- package/dist/extensions/list-read-scope.js.map +1 -1
- package/dist/pipeline/apiresource-labels.d.ts +2 -2
- package/dist/pipeline/apiresource-labels.js +2 -2
- package/dist/pipeline/errors.d.ts +2 -2
- package/dist/pipeline/errors.js +2 -2
- package/dist/pipeline/steps/authorize-resolved-target.d.ts +88 -0
- package/dist/pipeline/steps/authorize-resolved-target.d.ts.map +1 -0
- package/dist/pipeline/steps/authorize-resolved-target.js +36 -0
- package/dist/pipeline/steps/authorize-resolved-target.js.map +1 -0
- package/dist/pipeline/steps/authorize.d.ts +27 -0
- package/dist/pipeline/steps/authorize.d.ts.map +1 -1
- package/dist/pipeline/steps/authorize.js +49 -10
- package/dist/pipeline/steps/authorize.js.map +1 -1
- package/dist/pipeline/steps/guard-memory-capture.d.ts.map +1 -1
- package/dist/pipeline/steps/guard-memory-capture.js +2 -1
- package/dist/pipeline/steps/guard-memory-capture.js.map +1 -1
- package/dist/pipeline/steps/guard-reserved-labels.d.ts.map +1 -1
- package/dist/pipeline/steps/guard-reserved-labels.js +12 -12
- package/dist/pipeline/steps/guard-reserved-labels.js.map +1 -1
- package/dist/pipeline/steps/helpers.d.ts +9 -5
- package/dist/pipeline/steps/helpers.d.ts.map +1 -1
- package/dist/pipeline/steps/helpers.js +11 -15
- package/dist/pipeline/steps/helpers.js.map +1 -1
- package/dist/pipeline/steps/version-history.d.ts +11 -0
- package/dist/pipeline/steps/version-history.d.ts.map +1 -1
- package/dist/pipeline/steps/version-history.js +26 -0
- package/dist/pipeline/steps/version-history.js.map +1 -1
- package/package.json +6 -6
- package/src/authorization/__tests__/list-read-scope.test.ts +23 -12
- package/src/authorization/__tests__/skip-lane-inventory.test.ts +160 -0
- package/src/authorization/__tests__/wire-permissions.test.ts +5 -5
- package/src/authorization/evaluator.ts +7 -0
- package/src/authorization/list-read-scope.ts +22 -11
- package/src/authorization/model/__tests__/registry.test.ts +2 -0
- package/src/authorization/model/organization.ts +2 -0
- package/src/boot/compose.ts +0 -1
- package/src/boot/inprocess.ts +0 -9
- package/src/domain/agent/__tests__/agent.test.ts +0 -68
- package/src/domain/agent/controller.ts +11 -36
- package/src/domain/agent/steps.ts +1 -60
- package/src/domain/agentchannel/__tests__/create-authorization.test.ts +58 -0
- package/src/domain/agentchannel/controller.ts +19 -0
- package/src/domain/agentchannel/steps.ts +40 -0
- package/src/domain/agentexecution/__tests__/create-execution-context-step.test.ts +216 -0
- package/src/domain/agentexecution/__tests__/create-steps.test.ts +70 -145
- package/src/domain/agentexecution/controller.ts +6 -10
- package/src/domain/agentexecution/create-execution-context-step.ts +271 -83
- package/src/domain/agentexecution/create-steps.ts +38 -138
- package/src/domain/agentexecution/run-target.ts +7 -3
- package/src/domain/agentinstance/__tests__/create-authorization.composed.test.ts +243 -0
- package/src/domain/agentinstance/__tests__/create-authorization.test.ts +144 -0
- package/src/domain/agentinstance/controller.ts +24 -5
- package/src/domain/agentinstance/steps.ts +82 -8
- package/src/domain/agentshare/__tests__/create-authorization.test.ts +86 -0
- package/src/domain/agentshare/__tests__/member-audience.test.ts +113 -0
- package/src/domain/agentshare/controller.ts +21 -0
- package/src/domain/agentshare/steps.ts +181 -15
- package/src/domain/artifact/controller.ts +18 -22
- package/src/domain/channelapp/controller.ts +10 -0
- package/src/domain/environment/__tests__/personal.test.ts +143 -0
- package/src/domain/environment/controller.ts +10 -0
- package/src/domain/environment/personal.ts +141 -0
- package/src/domain/executioncontext/__tests__/executioncontext.test.ts +1 -0
- package/src/domain/executioncontext/controller.ts +10 -0
- package/src/domain/executioncontext/steps.ts +2 -1
- package/src/domain/mcpserver/connect.ts +32 -92
- package/src/domain/mcpserver/controller.ts +13 -1
- package/src/domain/mcpserver/start-connect.ts +17 -11
- package/src/domain/memory/__tests__/create-authorization.test.ts +59 -0
- package/src/domain/memory/controller.ts +11 -0
- package/src/domain/memory/steps.ts +41 -0
- package/src/domain/oauthapp/controller.ts +10 -0
- package/src/domain/plugin/controller.ts +22 -36
- package/src/domain/plugin/overlay/sanitize.ts +2 -2
- package/src/domain/schedule/__tests__/create-authorization.test.ts +58 -0
- package/src/domain/schedule/controller.ts +20 -0
- package/src/domain/schedule/steps.ts +45 -2
- package/src/domain/session/__tests__/run-gate.test.ts +19 -52
- package/src/domain/session/__tests__/session.test.ts +27 -203
- package/src/domain/session/controller.ts +10 -30
- package/src/domain/session/run-target.ts +9 -8
- package/src/domain/session/steps.ts +33 -267
- package/src/domain/skill/controller.ts +24 -23
- package/src/domain/workflow/controller.ts +58 -145
- package/src/domain/workflow/version-resolution.ts +166 -0
- package/src/domain/workflowexecution/create-steps.ts +4 -3
- package/src/domain/workflowinstance/__tests__/create-authorization.test.ts +109 -0
- package/src/domain/workflowinstance/controller.ts +19 -0
- package/src/domain/workflowinstance/steps.ts +49 -1
- package/src/extensions/__tests__/composed-support.ts +38 -4
- package/src/extensions/__tests__/identity.test.ts +44 -1
- package/src/extensions/__tests__/list-read-scope-composed.test.ts +87 -1
- package/src/extensions/__tests__/list-read-scope.test.ts +63 -0
- package/src/extensions/identity.ts +23 -5
- package/src/extensions/list-read-scope.ts +47 -7
- package/src/pipeline/apiresource-labels.ts +2 -2
- package/src/pipeline/errors.ts +2 -2
- package/src/pipeline/steps/__tests__/authorize-resolved-target.test.ts +285 -0
- package/src/pipeline/steps/authorize-resolved-target.ts +129 -0
- package/src/pipeline/steps/authorize.ts +70 -13
- package/src/pipeline/steps/guard-memory-capture.ts +2 -1
- package/src/pipeline/steps/guard-reserved-labels.ts +12 -14
- package/src/pipeline/steps/helpers.ts +11 -15
- package/src/pipeline/steps/version-history.ts +34 -0
- package/dist/domain/agent/defaultagent.d.ts +0 -37
- package/dist/domain/agent/defaultagent.d.ts.map +0 -1
- package/dist/domain/agent/defaultagent.js +0 -104
- package/dist/domain/agent/defaultagent.js.map +0 -1
- package/src/domain/agent/defaultagent.ts +0 -135
|
@@ -66,6 +66,10 @@ import {
|
|
|
66
66
|
authorizeDirect,
|
|
67
67
|
newAuthorizeStep,
|
|
68
68
|
} from "../../pipeline/steps/authorize.js";
|
|
69
|
+
import {
|
|
70
|
+
loadedTargetAsMethod,
|
|
71
|
+
newAuthorizeResolvedTargetStep,
|
|
72
|
+
} from "../../pipeline/steps/authorize-resolved-target.js";
|
|
69
73
|
import { newGuardReservedLabelsStep } from "../../pipeline/steps/guard-reserved-labels.js";
|
|
70
74
|
import { newBuildNewStateStep } from "../../pipeline/steps/defaults.js";
|
|
71
75
|
import { newBuildUpdateStateStep } from "../../pipeline/steps/build-update-state.js";
|
|
@@ -110,6 +114,7 @@ import {
|
|
|
110
114
|
newResolveChannelDefaultsStep,
|
|
111
115
|
newTeardownChannelRuntimeStep,
|
|
112
116
|
newValidateChannelUpdateStep,
|
|
117
|
+
resolveChannelCreateTargets,
|
|
113
118
|
} from "./steps.js";
|
|
114
119
|
|
|
115
120
|
export interface AgentChannelControllerDeps {
|
|
@@ -191,6 +196,14 @@ async function createChannel(
|
|
|
191
196
|
deps.channelRuntime,
|
|
192
197
|
),
|
|
193
198
|
)
|
|
199
|
+
// Before the duplicate check and the install state (steps.ts,
|
|
200
|
+
// resolveChannelCreateTargets).
|
|
201
|
+
.addStep(
|
|
202
|
+
newAuthorizeResolvedTargetStep(
|
|
203
|
+
deps.authorizer,
|
|
204
|
+
resolveChannelCreateTargets,
|
|
205
|
+
),
|
|
206
|
+
)
|
|
194
207
|
.addStep(newResolveSlugStep())
|
|
195
208
|
.addStep(newCheckDuplicateStep(deps.store))
|
|
196
209
|
.addStep(newBuildNewStateStep())
|
|
@@ -499,6 +512,12 @@ async function getByReference(
|
|
|
499
512
|
)
|
|
500
513
|
.addStep(newValidateProtoStep())
|
|
501
514
|
.addStep(newLoadByReferenceStep(deps.store, AgentChannelSchema))
|
|
515
|
+
.addStep(
|
|
516
|
+
newAuthorizeResolvedTargetStep(
|
|
517
|
+
deps.authorizer,
|
|
518
|
+
loadedTargetAsMethod(AgentChannelQueryController.method.get),
|
|
519
|
+
),
|
|
520
|
+
)
|
|
502
521
|
.build()
|
|
503
522
|
.execute(reqCtx);
|
|
504
523
|
return reqCtx.get(TARGET_RESOURCE_KEY) as AgentChannel;
|
|
@@ -21,7 +21,9 @@ import {
|
|
|
21
21
|
AgentChannelStatusSchema,
|
|
22
22
|
} from "@stigmer/protos/ai/stigmer/agentic/agentchannel/v1/status_pb";
|
|
23
23
|
import { AgentSchema } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/api_pb";
|
|
24
|
+
import type { Agent } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/api_pb";
|
|
24
25
|
import { ApiResourceKind } from "@stigmer/protos/ai/stigmer/commons/apiresource/apiresourcekind/api_resource_kind_pb";
|
|
26
|
+
import { IamPermission } from "@stigmer/protos/ai/stigmer/iam/v1/enum_pb";
|
|
25
27
|
|
|
26
28
|
import {
|
|
27
29
|
failedPreconditionError,
|
|
@@ -31,6 +33,7 @@ import {
|
|
|
31
33
|
} from "../../pipeline/errors.js";
|
|
32
34
|
import type { PipelineStep } from "../../pipeline/pipeline.js";
|
|
33
35
|
import type { RequestContext } from "../../pipeline/request-context.js";
|
|
36
|
+
import type { AuthorizationTarget } from "../../pipeline/steps/authorize.js";
|
|
34
37
|
import { findResourceBySlug } from "../../pipeline/steps/helpers.js";
|
|
35
38
|
import { EXISTING_RESOURCE_KEY } from "../../pipeline/steps/load-existing.js";
|
|
36
39
|
import type { Store } from "../../store/interface.js";
|
|
@@ -161,6 +164,7 @@ export function newResolveChannelDefaultsStep(
|
|
|
161
164
|
}
|
|
162
165
|
|
|
163
166
|
agentRef!.org = refOrg;
|
|
167
|
+
ctx.set(REFERENCED_AGENT_KEY, agent);
|
|
164
168
|
|
|
165
169
|
// Write-time constraints only a serving runtime can state (the
|
|
166
170
|
// pin-REQUIRED rule and its successors — channel-runtime.ts).
|
|
@@ -174,6 +178,42 @@ export function newResolveChannelDefaultsStep(
|
|
|
174
178
|
};
|
|
175
179
|
}
|
|
176
180
|
|
|
181
|
+
/**
|
|
182
|
+
* Context key for the agent ResolveChannelDefaults resolved from
|
|
183
|
+
* spec.agent_ref, read by the create lane's authorization step.
|
|
184
|
+
*/
|
|
185
|
+
export const REFERENCED_AGENT_KEY = "agentChannelReferencedAgent";
|
|
186
|
+
|
|
187
|
+
/** The deny copy of the create bar, the Java AgentChannelCreateHandler's. */
|
|
188
|
+
export const CHANNEL_CREATE_DENIED_MESSAGE =
|
|
189
|
+
"You don't have permission to connect this agent to a channel";
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* The create lane's authorization question, for AuthorizeResolvedTarget
|
|
193
|
+
* after ResolveChannelDefaults: can_edit on the REFERENCED AGENT. The RPC
|
|
194
|
+
* is is_skip_authorization because its target is that agent, resolved from
|
|
195
|
+
* a slug, not a request field. Binding an agent to a channel puts it in
|
|
196
|
+
* front of a wider audience, an editor's act; the same-org invariant the
|
|
197
|
+
* resolve step enforces already binds the channel's organization to the
|
|
198
|
+
* agent's, so there is no separate organization bar (command.proto).
|
|
199
|
+
*/
|
|
200
|
+
export function resolveChannelCreateTargets(
|
|
201
|
+
ctx: RequestContext<AgentChannelDesc>,
|
|
202
|
+
): ReadonlyArray<AuthorizationTarget> {
|
|
203
|
+
const agent = ctx.get(REFERENCED_AGENT_KEY) as Agent | undefined;
|
|
204
|
+
if (agent === undefined) {
|
|
205
|
+
throw new Error("referenced agent not found in context");
|
|
206
|
+
}
|
|
207
|
+
return [
|
|
208
|
+
{
|
|
209
|
+
permission: IamPermission.can_edit,
|
|
210
|
+
resourceKind: ApiResourceKind.agent,
|
|
211
|
+
resourceId: agent.metadata?.id ?? "",
|
|
212
|
+
deniedMessage: CHANNEL_CREATE_DENIED_MESSAGE,
|
|
213
|
+
},
|
|
214
|
+
];
|
|
215
|
+
}
|
|
216
|
+
|
|
177
217
|
/**
|
|
178
218
|
* InitInstallState — Go initInstallStateStep: writes
|
|
179
219
|
* status.install_state = pending_install; the channel exists but serves
|
|
@@ -6,6 +6,11 @@
|
|
|
6
6
|
* test driving a NON-EMPTY environment and a real token injection through
|
|
7
7
|
* buildAndPersistExecutionContext. Go has no unit twin (its coverage is
|
|
8
8
|
* the execution conformance suites); this pin is TS-only by design.
|
|
9
|
+
*
|
|
10
|
+
* Also pins the one declaration rule (the module header of the step): the
|
|
11
|
+
* agent's env united with the session servers' env, and a session
|
|
12
|
+
* server's saved key reaching the run from the personal environment — for
|
|
13
|
+
* an agent-bound run and for the built-in assistant alike.
|
|
9
14
|
*/
|
|
10
15
|
import { mkdtempSync, rmSync } from "node:fs";
|
|
11
16
|
import { tmpdir } from "node:os";
|
|
@@ -20,6 +25,7 @@ import { AgentInstanceSchema } from "@stigmer/protos/ai/stigmer/agentic/agentins
|
|
|
20
25
|
import { AgentExecutionSchema } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/api_pb";
|
|
21
26
|
import { EnvironmentSchema } from "@stigmer/protos/ai/stigmer/agentic/environment/v1/api_pb";
|
|
22
27
|
import type { EnvironmentValue } from "@stigmer/protos/ai/stigmer/agentic/environment/v1/spec_pb";
|
|
28
|
+
import { EnvironmentValueSchema } from "@stigmer/protos/ai/stigmer/agentic/environment/v1/spec_pb";
|
|
23
29
|
import type { ExecutionContext } from "@stigmer/protos/ai/stigmer/agentic/executioncontext/v1/api_pb";
|
|
24
30
|
import { McpServerSchema } from "@stigmer/protos/ai/stigmer/agentic/mcpserver/v1/api_pb";
|
|
25
31
|
import { SessionSchema } from "@stigmer/protos/ai/stigmer/agentic/session/v1/api_pb";
|
|
@@ -284,3 +290,213 @@ it("assembles merge → filter → OAuth injection → EC persist over a non-emp
|
|
|
284
290
|
const grant = await store.oauthGrants.find("", "mcps_vendor", ORG);
|
|
285
291
|
expect(grant?.accessTokenExpiresAt ?? 0).toBeGreaterThan(now);
|
|
286
292
|
});
|
|
293
|
+
|
|
294
|
+
// ---------------------------------------------------------------------------
|
|
295
|
+
// The one declaration rule: the run declares what its agent declares AND
|
|
296
|
+
// what its session's MCP servers declare, and a session server's declared
|
|
297
|
+
// variables the merge chain never carried (no instance layer can) come
|
|
298
|
+
// from the caller's personal environment by declared key. Two shapes, one
|
|
299
|
+
// rule: an agent-bound run whose session added a server, and the built-in
|
|
300
|
+
// assistant, which is the case with no agent half at all.
|
|
301
|
+
// ---------------------------------------------------------------------------
|
|
302
|
+
|
|
303
|
+
/** A personal environment reader over a fixed map; every read is recorded. */
|
|
304
|
+
function personalEnvironmentOver(
|
|
305
|
+
org: string,
|
|
306
|
+
data: Record<string, string>,
|
|
307
|
+
reads: string[],
|
|
308
|
+
): ReturnType<ExecutionContextBuilderDeps["environmentReader"]> {
|
|
309
|
+
return {
|
|
310
|
+
list: async () => ({
|
|
311
|
+
$typeName: "ai.stigmer.agentic.environment.v1.EnvironmentList",
|
|
312
|
+
totalCount: 1,
|
|
313
|
+
items: [
|
|
314
|
+
create(EnvironmentSchema, {
|
|
315
|
+
metadata: { id: "env_personal", org, slug: "personal" },
|
|
316
|
+
spec: {
|
|
317
|
+
data: Object.fromEntries(
|
|
318
|
+
Object.keys(data).map((key) => [key, { value: "***", isSecret: true }]),
|
|
319
|
+
),
|
|
320
|
+
},
|
|
321
|
+
}),
|
|
322
|
+
],
|
|
323
|
+
}),
|
|
324
|
+
getSecretValue: async (input) => {
|
|
325
|
+
const key = input.key ?? "";
|
|
326
|
+
reads.push(key);
|
|
327
|
+
return create(EnvironmentValueSchema, {
|
|
328
|
+
value: data[key] ?? "",
|
|
329
|
+
isSecret: true,
|
|
330
|
+
});
|
|
331
|
+
},
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
it("a session-level server's declared key saved in the personal environment reaches an agent-bound run", async () => {
|
|
336
|
+
const ORG = "acme";
|
|
337
|
+
await store.saveResource(
|
|
338
|
+
ApiResourceKind.mcp_server,
|
|
339
|
+
"mcps_github",
|
|
340
|
+
McpServerSchema,
|
|
341
|
+
create(McpServerSchema, {
|
|
342
|
+
metadata: { id: "mcps_github", org: ORG, slug: "github" },
|
|
343
|
+
spec: {
|
|
344
|
+
env: {
|
|
345
|
+
GITHUB_PAT: { isSecret: true },
|
|
346
|
+
GITHUB_ORG: { isSecret: false, optional: true },
|
|
347
|
+
},
|
|
348
|
+
},
|
|
349
|
+
}),
|
|
350
|
+
);
|
|
351
|
+
const agent = create(AgentSchema, {
|
|
352
|
+
metadata: { id: "agt_rule", org: ORG, slug: "rule-agent" },
|
|
353
|
+
// The agent declares its own key and nothing of the session's server.
|
|
354
|
+
spec: { env: { API_KEY: { isSecret: true } } },
|
|
355
|
+
});
|
|
356
|
+
const reads: string[] = [];
|
|
357
|
+
const createdEcs: ExecutionContext[] = [];
|
|
358
|
+
const deps: ExecutionContextBuilderDeps = {
|
|
359
|
+
store,
|
|
360
|
+
logger: silentLogger,
|
|
361
|
+
agentLoader: () => ({ get: async () => agent }),
|
|
362
|
+
agentInstanceLoader: () => ({
|
|
363
|
+
get: async (instanceId) =>
|
|
364
|
+
create(AgentInstanceSchema, {
|
|
365
|
+
metadata: { id: instanceId, org: ORG },
|
|
366
|
+
spec: { agentId: "agt_rule" },
|
|
367
|
+
}),
|
|
368
|
+
}),
|
|
369
|
+
sessionLoader: () => ({
|
|
370
|
+
get: async (sessionId) =>
|
|
371
|
+
create(SessionSchema, {
|
|
372
|
+
metadata: { id: sessionId, org: ORG },
|
|
373
|
+
spec: {
|
|
374
|
+
agentInstanceId: "agi_rule",
|
|
375
|
+
// Added at the session level: no instance, no environment_refs.
|
|
376
|
+
mcpServerUsages: [{ mcpServerRef: { slug: "github", org: ORG } }],
|
|
377
|
+
},
|
|
378
|
+
}),
|
|
379
|
+
}),
|
|
380
|
+
environmentReader: () =>
|
|
381
|
+
personalEnvironmentOver(ORG, { GITHUB_PAT: "ghp-saved", API_KEY: "never-read" }, reads),
|
|
382
|
+
environmentResolution: {
|
|
383
|
+
resolveByReference: async () => {
|
|
384
|
+
throw new Error("no environment refs on this instance");
|
|
385
|
+
},
|
|
386
|
+
} as unknown as ExecutionContextBuilderDeps["environmentResolution"],
|
|
387
|
+
executionContextCreator: () => ({
|
|
388
|
+
create: async (ec) => {
|
|
389
|
+
createdEcs.push(ec);
|
|
390
|
+
return ec;
|
|
391
|
+
},
|
|
392
|
+
}),
|
|
393
|
+
managedEnvService: {
|
|
394
|
+
readSecretValue: async () => "",
|
|
395
|
+
updateSecrets: async () => {},
|
|
396
|
+
} as unknown as ManagedEnvironmentService,
|
|
397
|
+
};
|
|
398
|
+
const execution = create(AgentExecutionSchema, {
|
|
399
|
+
metadata: { id: "aexec_rule", org: ORG },
|
|
400
|
+
spec: {
|
|
401
|
+
sessionId: "ses_rule",
|
|
402
|
+
message: "hi",
|
|
403
|
+
runtimeEnv: {
|
|
404
|
+
API_KEY: { value: "runtime", isSecret: true },
|
|
405
|
+
UNDECLARED: { value: "stripped", isSecret: false },
|
|
406
|
+
},
|
|
407
|
+
},
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
await buildAndPersistExecutionContext(deps, execution, "");
|
|
411
|
+
|
|
412
|
+
const data = createdEcs[0]?.spec?.data ?? {};
|
|
413
|
+
// The agent's own key still flows as before.
|
|
414
|
+
expect(data["API_KEY"]?.value).toBe("runtime");
|
|
415
|
+
// The session server's declared key survives the filter (the union) and
|
|
416
|
+
// is resolved from the personal environment, marked secret as declared.
|
|
417
|
+
expect(data["GITHUB_PAT"]?.value).toBe("ghp-saved");
|
|
418
|
+
expect(data["GITHUB_PAT"]?.isSecret).toBe(true);
|
|
419
|
+
// A key nobody declared is filtered, as before.
|
|
420
|
+
expect(data["UNDECLARED"]).toBeUndefined();
|
|
421
|
+
// Least privilege: only the session server's still-missing declared key
|
|
422
|
+
// the personal environment HOLDS was read — never the agent's (already
|
|
423
|
+
// present), never a key the environment lacks (the optional one is
|
|
424
|
+
// skipped on the stored-keys check, no secret read), never the whole
|
|
425
|
+
// environment.
|
|
426
|
+
expect(reads).toEqual(["GITHUB_PAT"]);
|
|
427
|
+
expect(data["GITHUB_ORG"]).toBeUndefined();
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
it("the built-in assistant: no instance, no agent, the session's servers are the declared set", async () => {
|
|
431
|
+
const ORG = "acme";
|
|
432
|
+
await store.saveResource(
|
|
433
|
+
ApiResourceKind.mcp_server,
|
|
434
|
+
"mcps_notes",
|
|
435
|
+
McpServerSchema,
|
|
436
|
+
create(McpServerSchema, {
|
|
437
|
+
metadata: { id: "mcps_notes", org: ORG, slug: "notes" },
|
|
438
|
+
spec: { env: { NOTES_TOKEN: { isSecret: true } } },
|
|
439
|
+
}),
|
|
440
|
+
);
|
|
441
|
+
const reads: string[] = [];
|
|
442
|
+
const createdEcs: ExecutionContext[] = [];
|
|
443
|
+
const deps: ExecutionContextBuilderDeps = {
|
|
444
|
+
store,
|
|
445
|
+
logger: silentLogger,
|
|
446
|
+
// Neither lane may be reached: there is no instance and no agent.
|
|
447
|
+
agentLoader: () => ({
|
|
448
|
+
get: async () => {
|
|
449
|
+
throw new Error("agent loader must not be reached");
|
|
450
|
+
},
|
|
451
|
+
}),
|
|
452
|
+
agentInstanceLoader: () => ({
|
|
453
|
+
get: async () => {
|
|
454
|
+
throw new Error("instance loader must not be reached");
|
|
455
|
+
},
|
|
456
|
+
}),
|
|
457
|
+
sessionLoader: () => ({
|
|
458
|
+
get: async (sessionId) =>
|
|
459
|
+
create(SessionSchema, {
|
|
460
|
+
metadata: { id: sessionId, org: ORG },
|
|
461
|
+
spec: {
|
|
462
|
+
agentInstanceId: "",
|
|
463
|
+
mcpServerUsages: [{ mcpServerRef: { slug: "notes", org: ORG } }],
|
|
464
|
+
},
|
|
465
|
+
}),
|
|
466
|
+
}),
|
|
467
|
+
environmentReader: () => personalEnvironmentOver(ORG, { NOTES_TOKEN: "nt-saved" }, reads),
|
|
468
|
+
environmentResolution: {
|
|
469
|
+
resolveByReference: async () => {
|
|
470
|
+
throw new Error("no environment refs without an instance");
|
|
471
|
+
},
|
|
472
|
+
} as unknown as ExecutionContextBuilderDeps["environmentResolution"],
|
|
473
|
+
executionContextCreator: () => ({
|
|
474
|
+
create: async (ec) => {
|
|
475
|
+
createdEcs.push(ec);
|
|
476
|
+
return ec;
|
|
477
|
+
},
|
|
478
|
+
}),
|
|
479
|
+
managedEnvService: {
|
|
480
|
+
readSecretValue: async () => "",
|
|
481
|
+
updateSecrets: async () => {},
|
|
482
|
+
} as unknown as ManagedEnvironmentService,
|
|
483
|
+
};
|
|
484
|
+
const execution = create(AgentExecutionSchema, {
|
|
485
|
+
metadata: { id: "aexec_assistant", org: ORG },
|
|
486
|
+
spec: {
|
|
487
|
+
sessionId: "ses_assistant",
|
|
488
|
+
message: "hi",
|
|
489
|
+
runtimeEnv: { STRAY: { value: "stripped", isSecret: false } },
|
|
490
|
+
},
|
|
491
|
+
});
|
|
492
|
+
|
|
493
|
+
await buildAndPersistExecutionContext(deps, execution, "");
|
|
494
|
+
|
|
495
|
+
expect(createdEcs).toHaveLength(1);
|
|
496
|
+
const data = createdEcs[0]?.spec?.data ?? {};
|
|
497
|
+
expect(data["NOTES_TOKEN"]?.value).toBe("nt-saved");
|
|
498
|
+
// The declared set is the session servers' alone, so the filter is
|
|
499
|
+
// live: a stray runtime key is stripped, not passed through.
|
|
500
|
+
expect(data["STRAY"]).toBeUndefined();
|
|
501
|
+
expect(reads).toEqual(["NOTES_TOKEN"]);
|
|
502
|
+
});
|
|
@@ -19,7 +19,6 @@ import type { JsonObject } from "@bufbuild/protobuf";
|
|
|
19
19
|
import { Code, ConnectError } from "@connectrpc/connect";
|
|
20
20
|
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
21
21
|
|
|
22
|
-
import { AgentSchema } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/api_pb";
|
|
23
22
|
import type { AgentExecution } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/api_pb";
|
|
24
23
|
import {
|
|
25
24
|
AgentExecutionSchema,
|
|
@@ -32,6 +31,8 @@ import {
|
|
|
32
31
|
} from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/spec_pb";
|
|
33
32
|
import { MemorySchema } from "@stigmer/protos/ai/stigmer/agentic/memory/v1/api_pb";
|
|
34
33
|
import { MemoryLifecycleState } from "@stigmer/protos/ai/stigmer/agentic/memory/v1/enum_pb";
|
|
34
|
+
import type { Session } from "@stigmer/protos/ai/stigmer/agentic/session/v1/api_pb";
|
|
35
|
+
import { SessionSchema } from "@stigmer/protos/ai/stigmer/agentic/session/v1/api_pb";
|
|
35
36
|
import type { SessionSpec } from "@stigmer/protos/ai/stigmer/agentic/session/v1/spec_pb";
|
|
36
37
|
import { SessionSpecSchema } from "@stigmer/protos/ai/stigmer/agentic/session/v1/spec_pb";
|
|
37
38
|
import {
|
|
@@ -42,7 +43,6 @@ import type { Workflow } from "@stigmer/protos/ai/stigmer/agentic/workflow/v1/ap
|
|
|
42
43
|
import { WorkflowSchema } from "@stigmer/protos/ai/stigmer/agentic/workflow/v1/api_pb";
|
|
43
44
|
import { WorkflowTaskKind } from "@stigmer/protos/ai/stigmer/agentic/workflow/v1/enum_pb";
|
|
44
45
|
import { ApiResourceKind } from "@stigmer/protos/ai/stigmer/commons/apiresource/apiresourcekind/api_resource_kind_pb";
|
|
45
|
-
import { ApiResourceVisibility } from "@stigmer/protos/ai/stigmer/commons/apiresource/enum_pb";
|
|
46
46
|
import { OrganizationSchema } from "@stigmer/protos/ai/stigmer/tenancy/organization/v1/api_pb";
|
|
47
47
|
|
|
48
48
|
import { createLogger } from "../../../boot/logger.js";
|
|
@@ -59,8 +59,6 @@ import {
|
|
|
59
59
|
newComposeRecalledMemoriesStep,
|
|
60
60
|
newCreateDefaultInstanceIfNeededStep,
|
|
61
61
|
newCreateSessionIfNeededStep,
|
|
62
|
-
newEnsureSessionOrAgentResolvedStep,
|
|
63
|
-
newResolveDefaultAgentStep,
|
|
64
62
|
newStartWorkflowStep,
|
|
65
63
|
} from "../create-steps.js";
|
|
66
64
|
import type { AgentExecutionStatusTransition } from "../../../extensions/status-hooks.js";
|
|
@@ -105,28 +103,6 @@ function newContext(
|
|
|
105
103
|
);
|
|
106
104
|
}
|
|
107
105
|
|
|
108
|
-
async function seedDefaultAgent(
|
|
109
|
-
id: string,
|
|
110
|
-
visibility: ApiResourceVisibility,
|
|
111
|
-
): Promise<void> {
|
|
112
|
-
await store.saveResource(
|
|
113
|
-
ApiResourceKind.agent,
|
|
114
|
-
id,
|
|
115
|
-
AgentSchema,
|
|
116
|
-
create(AgentSchema, {
|
|
117
|
-
apiVersion: "agentic.stigmer.ai/v1",
|
|
118
|
-
kind: "Agent",
|
|
119
|
-
metadata: {
|
|
120
|
-
id,
|
|
121
|
-
name: "assistant",
|
|
122
|
-
org: "stigmer",
|
|
123
|
-
visibility,
|
|
124
|
-
labels: { "stigmer.ai/default-agent": "true" },
|
|
125
|
-
},
|
|
126
|
-
}),
|
|
127
|
-
);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
106
|
async function expectCode(
|
|
131
107
|
fn: () => Promise<unknown> | unknown,
|
|
132
108
|
code: Code,
|
|
@@ -141,140 +117,89 @@ async function expectCode(
|
|
|
141
117
|
throw new Error(`expected code ${Code[code]}, call succeeded`);
|
|
142
118
|
}
|
|
143
119
|
|
|
144
|
-
// The
|
|
145
|
-
//
|
|
146
|
-
//
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
sessionId: "ses_1",
|
|
162
|
-
agentId: "agt_1",
|
|
163
|
-
},
|
|
164
|
-
{
|
|
165
|
-
name: "session_spec instance resolved -> pass",
|
|
166
|
-
specInstanceId: "inst_1",
|
|
167
|
-
},
|
|
168
|
-
{
|
|
169
|
-
name: "none resolved -> Internal invariant violation",
|
|
170
|
-
wantCode: Code.Internal,
|
|
171
|
-
},
|
|
172
|
-
];
|
|
173
|
-
|
|
174
|
-
for (const tt of cases) {
|
|
175
|
-
it(tt.name, async () => {
|
|
176
|
-
const execution = newExecution(tt.sessionId ?? "", tt.agentId ?? "");
|
|
177
|
-
if (tt.specInstanceId !== undefined) {
|
|
178
|
-
execution.spec!.sessionSpec = create(SessionSpecSchema, {
|
|
179
|
-
agentInstanceId: tt.specInstanceId,
|
|
180
|
-
});
|
|
181
|
-
}
|
|
182
|
-
const ctx = newContext(execution);
|
|
183
|
-
if (tt.wantCode === undefined) {
|
|
184
|
-
await step.execute(ctx);
|
|
185
|
-
} else {
|
|
186
|
-
await expectCode(() => step.execute(ctx), tt.wantCode);
|
|
187
|
-
}
|
|
120
|
+
// The built-in assistant's shape through the two side-effecting steps: an
|
|
121
|
+
// execution naming no session, no agent and no session_spec instance is
|
|
122
|
+
// legal (agentexecution/v1/spec.proto), so CreateDefaultInstanceIfNeeded
|
|
123
|
+
// has nothing to load or mint and CreateSessionIfNeeded creates the
|
|
124
|
+
// session with an EMPTY agent_instance_id. The throwing providers prove
|
|
125
|
+
// the first step never reaches a client (Go's nil clients would panic).
|
|
126
|
+
describe("the built-in assistant (no session, agent or instance named)", () => {
|
|
127
|
+
it("createDefaultInstanceIfNeeded skips without touching the agent lane", async () => {
|
|
128
|
+
const step = newCreateDefaultInstanceIfNeededStep({
|
|
129
|
+
store,
|
|
130
|
+
logger: silentLogger,
|
|
131
|
+
agentLoader: () => {
|
|
132
|
+
throw new Error("agent loader must not be reached");
|
|
133
|
+
},
|
|
134
|
+
agentInstanceCreator: () => {
|
|
135
|
+
throw new Error("instance creator must not be reached");
|
|
136
|
+
},
|
|
188
137
|
});
|
|
189
|
-
}
|
|
190
|
-
});
|
|
191
|
-
|
|
192
|
-
// The reachable contract of default-agent resolution: NotFound when
|
|
193
|
-
// unseeded, resolution onto newState when a public default exists, and
|
|
194
|
-
// FailedPrecondition when the default is not visibility_public.
|
|
195
|
-
describe("newResolveDefaultAgentStep", () => {
|
|
196
|
-
it("no default agent seeded -> NotFound", async () => {
|
|
197
|
-
const step = newResolveDefaultAgentStep(store, silentLogger);
|
|
198
|
-
await expectCode(
|
|
199
|
-
() => step.execute(newContext(newExecution("", ""))),
|
|
200
|
-
Code.NotFound,
|
|
201
|
-
);
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
it("public default agent -> resolves agent_id onto newState", async () => {
|
|
205
|
-
await seedDefaultAgent(
|
|
206
|
-
"agt_default",
|
|
207
|
-
ApiResourceVisibility.visibility_public,
|
|
208
|
-
);
|
|
209
|
-
const step = newResolveDefaultAgentStep(store, silentLogger);
|
|
210
138
|
const ctx = newContext(newExecution("", ""));
|
|
211
|
-
|
|
212
139
|
await step.execute(ctx);
|
|
213
|
-
|
|
214
|
-
expect(ctx.newState.spec?.agentId).toBe("agt_default");
|
|
215
|
-
// The original request must remain immutable.
|
|
216
|
-
expect(ctx.input.spec?.agentId).toBe("");
|
|
217
|
-
});
|
|
218
|
-
|
|
219
|
-
it("non-public default agent -> FailedPrecondition", async () => {
|
|
220
|
-
await seedDefaultAgent(
|
|
221
|
-
"agt_private",
|
|
222
|
-
ApiResourceVisibility.visibility_private,
|
|
223
|
-
);
|
|
224
|
-
const step = newResolveDefaultAgentStep(store, silentLogger);
|
|
225
|
-
await expectCode(
|
|
226
|
-
() => step.execute(newContext(newExecution("", ""))),
|
|
227
|
-
Code.FailedPrecondition,
|
|
228
|
-
);
|
|
140
|
+
expect(ctx.get(DEFAULT_INSTANCE_ID_KEY)).toBeUndefined();
|
|
229
141
|
});
|
|
230
142
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
id,
|
|
243
|
-
id === "agt_1public"
|
|
244
|
-
? ApiResourceVisibility.visibility_public
|
|
245
|
-
: ApiResourceVisibility.visibility_private,
|
|
246
|
-
);
|
|
247
|
-
}
|
|
248
|
-
const step = newResolveDefaultAgentStep(store, silentLogger);
|
|
249
|
-
const ctx = newContext(newExecution("", ""));
|
|
250
|
-
await step.execute(ctx);
|
|
251
|
-
expect(ctx.newState.spec?.agentId).toBe("agt_1public");
|
|
143
|
+
it("createSessionIfNeeded creates the session with no instance and no context key", async () => {
|
|
144
|
+
let created: Session | undefined;
|
|
145
|
+
const step = newCreateSessionIfNeededStep({
|
|
146
|
+
logger: silentLogger,
|
|
147
|
+
sessionCreator: () => ({
|
|
148
|
+
createAsCaller: async (session) => {
|
|
149
|
+
created = clone(SessionSchema, session);
|
|
150
|
+
created.metadata!.id = "ses_assistant";
|
|
151
|
+
return created;
|
|
152
|
+
},
|
|
153
|
+
}),
|
|
252
154
|
});
|
|
253
|
-
|
|
155
|
+
const execution = newExecution("", "");
|
|
156
|
+
execution.metadata!.org = "acme";
|
|
157
|
+
const ctx = newContext(execution);
|
|
254
158
|
|
|
255
|
-
it("reference already provided -> no-op", async () => {
|
|
256
|
-
const step = newResolveDefaultAgentStep(store, silentLogger);
|
|
257
|
-
const ctx = newContext(newExecution("", "agt_explicit"));
|
|
258
159
|
await step.execute(ctx);
|
|
259
|
-
|
|
160
|
+
|
|
161
|
+
expect(created?.spec?.agentInstanceId).toBe("");
|
|
162
|
+
expect(created?.spec?.subject).toBe(AUTO_CREATED_SESSION_SUBJECT);
|
|
163
|
+
expect(created?.metadata?.org).toBe("acme");
|
|
164
|
+
expect(ctx.newState.spec?.sessionId).toBe("ses_assistant");
|
|
165
|
+
expect(ctx.newState.spec?.sessionSpec).toBeUndefined();
|
|
260
166
|
});
|
|
261
167
|
|
|
262
|
-
it("
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
168
|
+
it("createSessionIfNeeded forwards a caller session_spec that names no instance", async () => {
|
|
169
|
+
let created: Session | undefined;
|
|
170
|
+
const step = newCreateSessionIfNeededStep({
|
|
171
|
+
logger: silentLogger,
|
|
172
|
+
sessionCreator: () => ({
|
|
173
|
+
createAsCaller: async (session) => {
|
|
174
|
+
created = clone(SessionSchema, session);
|
|
175
|
+
created.metadata!.id = "ses_assistant_tools";
|
|
176
|
+
return created;
|
|
177
|
+
},
|
|
178
|
+
}),
|
|
179
|
+
});
|
|
271
180
|
const execution = newExecution("", "");
|
|
272
181
|
execution.spec!.sessionSpec = create(SessionSpecSchema, {
|
|
273
|
-
|
|
182
|
+
mcpServerUsages: [{ mcpServerRef: { org: "acme", slug: "github" } }],
|
|
274
183
|
});
|
|
275
184
|
const ctx = newContext(execution);
|
|
185
|
+
|
|
276
186
|
await step.execute(ctx);
|
|
277
|
-
|
|
187
|
+
|
|
188
|
+
expect(created?.spec?.agentInstanceId).toBe("");
|
|
189
|
+
expect(created?.spec?.mcpServerUsages.map((u) => u.mcpServerRef?.slug)).toEqual(["github"]);
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
// An agent WAS named but the previous step left no key: the invariant
|
|
193
|
+
// guard stays Internal, unchanged — only the all-empty shape is legal.
|
|
194
|
+
it("createSessionIfNeeded still refuses a named agent whose instance was never resolved", async () => {
|
|
195
|
+
const step = newCreateSessionIfNeededStep({
|
|
196
|
+
logger: silentLogger,
|
|
197
|
+
sessionCreator: () => {
|
|
198
|
+
throw new Error("session creator must not be reached");
|
|
199
|
+
},
|
|
200
|
+
});
|
|
201
|
+
const ctx = newContext(newExecution("", "agt_named"));
|
|
202
|
+
await expectCode(() => step.execute(ctx), Code.Internal);
|
|
278
203
|
});
|
|
279
204
|
});
|
|
280
205
|
|
|
@@ -94,9 +94,7 @@ import {
|
|
|
94
94
|
newComposeRecalledMemoriesStep,
|
|
95
95
|
newCreateDefaultInstanceIfNeededStep,
|
|
96
96
|
newCreateSessionIfNeededStep,
|
|
97
|
-
newEnsureSessionOrAgentResolvedStep,
|
|
98
97
|
newProcessAttachmentsStep,
|
|
99
|
-
newResolveDefaultAgentStep,
|
|
100
98
|
newSetInitialPhaseStep,
|
|
101
99
|
newStartWorkflowStep,
|
|
102
100
|
} from "./create-steps.js";
|
|
@@ -280,12 +278,12 @@ export function registerAgentExecutionServices(
|
|
|
280
278
|
|
|
281
279
|
/**
|
|
282
280
|
* Create — create.go buildCreatePipeline, step-for-step: validation
|
|
283
|
-
* (proto → visibility → tier #357 → thinking #772) →
|
|
284
|
-
* (
|
|
285
|
-
*
|
|
286
|
-
* the
|
|
287
|
-
*
|
|
288
|
-
* about engine state, and before every side effect) → the standard build
|
|
281
|
+
* (proto → visibility → tier #357 → thinking #772) → the run gate
|
|
282
|
+
* (AuthorizeRunTarget, P1 sp.run-gate: asking the target's own permission
|
|
283
|
+
* by request shape — session, instance or blueprint; the all-empty shape
|
|
284
|
+
* is the built-in assistant, admitted by Authorize's organization check
|
|
285
|
+
* and gated on nothing further — before the engine gate so a denied caller
|
|
286
|
+
* learns nothing about engine state, and before every side effect) → the standard build
|
|
289
287
|
* → the engine gate (fail fast BEFORE the first side effect, so a down
|
|
290
288
|
* engine orphans nothing) → the pre-side-effect gate slot (O4; empty in OSS) → the
|
|
291
289
|
* side-effecting steps (default instance, session bootstrap,
|
|
@@ -319,8 +317,6 @@ async function createExecution(
|
|
|
319
317
|
.addStep(newValidateVisibilityStep())
|
|
320
318
|
.addStep(newValidateServiceTierStep(deps.modelRegistry))
|
|
321
319
|
.addStep(newValidateThinkingModeStep(deps.modelRegistry))
|
|
322
|
-
.addStep(newResolveDefaultAgentStep(deps.store, deps.logger))
|
|
323
|
-
.addStep(newEnsureSessionOrAgentResolvedStep(deps.logger))
|
|
324
320
|
.addStep(
|
|
325
321
|
newAuthorizeRunTargetStep(deps.authorizer, agentExecutionRunTarget),
|
|
326
322
|
)
|