Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -625,7 +625,9 @@ public sealed class DraftBehavior : ScriptBehavior<AppScriptReadModel, AppScript
expect(headerScope.getByText('Scope 1626c177…b0d6')).toBeTruthy();
expect(headerScope.getByRole('button', { name: 'New draft' })).toBeTruthy();
expect(headerScope.getByRole('button', { name: 'Save' })).toBeTruthy();
expect(headerScope.getByRole('button', { name: 'Bind scope' })).toBeTruthy();
expect(
headerScope.getByRole('button', { name: 'Update default route' }),
).toBeTruthy();
fireEvent.click(
headerScope.getByRole('button', { name: 'More script actions' }),
);
Expand Down Expand Up @@ -731,7 +733,9 @@ public sealed class DraftBehavior : ScriptBehavior<AppScriptReadModel, AppScript
expect(mockedScriptsApi.saveScript).toHaveBeenCalledTimes(1);
});

fireEvent.click(screen.getByRole('button', { name: 'Bind scope' }));
fireEvent.click(
screen.getByRole('button', { name: 'Update default route' }),
);

await waitFor(() => {
expect(screen.getByText('Bind saved script')).toBeTruthy();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1501,12 +1501,12 @@ const ScriptsWorkbenchPage: React.FC<ScriptsWorkbenchPageProps> = ({
await queryClient.invalidateQueries({
queryKey: ['studio-scripts-catalogs', appContext.scopeId],
});
const bindingScopeIds = Array.from(
const defaultRouteScopeIds = Array.from(
new Set([appContext.scopeId, resolvedScopeId].filter(Boolean)),
);
for (const scopeId of bindingScopeIds) {
for (const scopeId of defaultRouteScopeIds) {
await queryClient.invalidateQueries({
queryKey: ['studio-scope-binding', scopeId],
queryKey: ['studio-default-route', scopeId],
});
}
}, [appContext.scopeId, queryClient, resolvedScopeId]);
Expand Down Expand Up @@ -2672,7 +2672,7 @@ const ScriptsWorkbenchPage: React.FC<ScriptsWorkbenchPageProps> = ({
className="console-scripts-solid-action console-scripts-header-text-action"
onClick={handleOpenBindScope}
disabled={!canBindScope}
aria-label="Bind scope"
aria-label="Update default route"
>
<SafetyCertificateOutlined />
<span>Bind</span>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ const consoleFlows: readonly ConsoleFlow[] = [
{
badge: "Recommended first",
description:
"Check the scope binding, published services, deployed workflows, or inspect an actor directly.",
"Check the default route target, published services, deployed workflows, or inspect an actor directly.",
group: "understand",
id: "query",
label: "Query",
Expand Down Expand Up @@ -702,7 +702,7 @@ export function ChatAdvancedConsole({
let result: unknown;
switch (queryTarget) {
case "binding":
result = await studioApi.getScopeBinding(scopeId);
result = await studioApi.getDefaultRouteTarget(scopeId);
break;
case "services":
result = await servicesApi.listServices({
Expand Down
5 changes: 5 additions & 0 deletions apps/aevatar-console-web/src/pages/chat/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,11 @@ jest.mock("@/shared/studio/api", () => ({
scopeId: "scope-a",
serviceId: "support-service",
})),
getDefaultRouteTarget: jest.fn(async () => ({
available: true,
scopeId: "scope-a",
serviceId: "support-service",
})),
getUserConfig: jest.fn(async () => ({
defaultModel: "",
preferredLlmRoute: "",
Expand Down
28 changes: 18 additions & 10 deletions apps/aevatar-console-web/src/pages/chat/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -386,10 +386,10 @@ const ChatPage: React.FC = () => {
queryFn: () => studioApi.getUserConfigModels(),
});

const bindingQuery = useQuery({
const defaultRouteTargetQuery = useQuery({
enabled: scopeId.length > 0,
queryKey: ["chat", "binding", scopeId],
queryFn: () => studioApi.getScopeBinding(scopeId),
queryKey: ["chat", "default-route-target", scopeId],
queryFn: () => studioApi.getDefaultRouteTarget(scopeId),
});
const servicesQuery = useQuery({
enabled: scopeId.length > 0,
Expand All @@ -407,13 +407,19 @@ const ChatPage: React.FC = () => {
createOnboardingServiceOption(),
...buildScopeConsoleServiceOptions(
servicesQuery.data ?? [],
bindingQuery.data?.available ? bindingQuery.data.serviceId : undefined,
defaultRouteTargetQuery.data?.available
? defaultRouteTargetQuery.data.serviceId
: undefined,
{
chatOnly: true,
}
).map(mapChatServiceOption),
],
[bindingQuery.data?.available, bindingQuery.data?.serviceId, servicesQuery.data]
[
defaultRouteTargetQuery.data?.available,
defaultRouteTargetQuery.data?.serviceId,
servicesQuery.data,
]
);
const providerConfigured = useMemo(
() => hasConfiguredProviders(settingsQuery.data?.providers ?? []),
Expand Down Expand Up @@ -575,14 +581,16 @@ const ChatPage: React.FC = () => {
const onboardingPreferredServiceId =
settingsQuery.isSuccess &&
!providerConfigured &&
!bindingQuery.data?.available &&
!defaultRouteTargetQuery.data?.available &&
services.some((service) => service.id === onboardingServiceId)
? onboardingServiceId
: "";
const preferredServiceId =
routePreferredServiceId ||
onboardingPreferredServiceId ||
(bindingQuery.data?.available ? bindingQuery.data.serviceId : "") ||
(defaultRouteTargetQuery.data?.available
? defaultRouteTargetQuery.data.serviceId
: "") ||
services.find((service) => service.id === nyxIdChatServiceId)?.id ||
services[0]?.id ||
"";
Expand All @@ -609,8 +617,8 @@ const ChatPage: React.FC = () => {
}
}, [
activeConversationId,
bindingQuery.data?.available,
bindingQuery.data?.serviceId,
defaultRouteTargetQuery.data?.available,
defaultRouteTargetQuery.data?.serviceId,
isStreaming,
messages.length,
providerConfigured,
Expand Down Expand Up @@ -2197,7 +2205,7 @@ const ChatPage: React.FC = () => {
"Open Tools only when you need audit evidence or protocol-level detail.",
]
: [
"Ask NyxID to inspect services, credentials, or scope bindings.",
"Ask NyxID to inspect services, credentials, or default route targets.",
"Use natural-language prompts first, then open Tools for deeper runtime evidence.",
"Keep model and route overrides in the composer footer when you need a specific provider path.",
]
Expand Down
22 changes: 14 additions & 8 deletions apps/aevatar-console-web/src/pages/gagents/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,12 @@ jest.mock("@/shared/api/runtimeGAgentApi", () => ({
listTypes: jest.fn(),
listActors: jest.fn(),
getScopeBinding: jest.fn(),
getDefaultRouteTarget: jest.fn(),
bindScopeGAgent: jest.fn(),
activateScopeBindingRevision: jest.fn(),
activateMemberBindingRevision: jest.fn(),
retireScopeBindingRevision: jest.fn(),
retireMemberBindingRevision: jest.fn(),
addActor: jest.fn(),
removeActor: jest.fn(),
streamDraftRun: jest.fn(),
Expand Down Expand Up @@ -106,9 +109,12 @@ describe("GAgentsPage", () => {
listTypes: jest.Mock;
listActors: jest.Mock;
getScopeBinding: jest.Mock;
getDefaultRouteTarget: jest.Mock;
bindScopeGAgent: jest.Mock;
activateScopeBindingRevision: jest.Mock;
activateMemberBindingRevision: jest.Mock;
retireScopeBindingRevision: jest.Mock;
retireMemberBindingRevision: jest.Mock;
addActor: jest.Mock;
removeActor: jest.Mock;
streamDraftRun: jest.Mock;
Expand Down Expand Up @@ -154,7 +160,7 @@ describe("GAgentsPage", () => {
actorIds: ["planner-1"],
},
];
mockedRuntimeGAgentApi.getScopeBinding.mockResolvedValue({
mockedRuntimeGAgentApi.getDefaultRouteTarget.mockResolvedValue({
available: false,
scopeId: "scope-a",
serviceId: "",
Expand All @@ -181,13 +187,13 @@ describe("GAgentsPage", () => {
preferredActorId: "orders-1",
},
});
mockedRuntimeGAgentApi.activateScopeBindingRevision.mockResolvedValue({
mockedRuntimeGAgentApi.activateMemberBindingRevision.mockResolvedValue({
scopeId: "scope-a",
serviceId: "service-orders",
displayName: "Orders Assistant",
revisionId: "rev-2",
});
mockedRuntimeGAgentApi.retireScopeBindingRevision.mockResolvedValue({
mockedRuntimeGAgentApi.retireMemberBindingRevision.mockResolvedValue({
scopeId: "scope-a",
serviceId: "service-orders",
revisionId: "rev-2",
Expand Down Expand Up @@ -400,7 +406,7 @@ describe("GAgentsPage", () => {
});

it("surfaces the current binding and active binding type in the workbench", async () => {
mockedRuntimeGAgentApi.getScopeBinding.mockResolvedValue({
mockedRuntimeGAgentApi.getDefaultRouteTarget.mockResolvedValue({
available: true,
scopeId: "scope-a",
serviceId: "service-orders",
Expand Down Expand Up @@ -453,7 +459,7 @@ describe("GAgentsPage", () => {
});

it("requires acknowledgement before replacing a published binding and then publishes the revision", async () => {
mockedRuntimeGAgentApi.getScopeBinding.mockResolvedValue({
mockedRuntimeGAgentApi.getDefaultRouteTarget.mockResolvedValue({
available: true,
scopeId: "scope-a",
serviceId: "service-orders",
Expand Down Expand Up @@ -549,7 +555,7 @@ describe("GAgentsPage", () => {
});

it("activates and retires a selectable binding revision", async () => {
mockedRuntimeGAgentApi.getScopeBinding.mockResolvedValue({
mockedRuntimeGAgentApi.getDefaultRouteTarget.mockResolvedValue({
available: true,
scopeId: "scope-a",
serviceId: "service-orders",
Expand Down Expand Up @@ -625,7 +631,7 @@ describe("GAgentsPage", () => {
fireEvent.click(await screen.findByRole("button", { name: "Activate" }));
await waitFor(() => {
expect(
mockedRuntimeGAgentApi.activateScopeBindingRevision
mockedRuntimeGAgentApi.activateMemberBindingRevision
).toHaveBeenCalledWith("scope-a", "rev-2");
});
expect(
Expand All @@ -640,7 +646,7 @@ describe("GAgentsPage", () => {

await waitFor(() => {
expect(
mockedRuntimeGAgentApi.retireScopeBindingRevision
mockedRuntimeGAgentApi.retireMemberBindingRevision
).toHaveBeenCalledWith("scope-a", "rev-2");
});
expect(
Expand Down
6 changes: 3 additions & 3 deletions apps/aevatar-console-web/src/pages/gagents/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -453,7 +453,7 @@ const GAgentsPage: React.FC = () => {
const bindingQuery = useQuery({
enabled: normalizedScopeId.length > 0,
queryKey: ['runtime-gagents', 'binding', normalizedScopeId],
queryFn: () => runtimeGAgentApi.getScopeBinding(normalizedScopeId),
queryFn: () => runtimeGAgentApi.getDefaultRouteTarget(normalizedScopeId),
retry: false,
});

Expand Down Expand Up @@ -1119,7 +1119,7 @@ const GAgentsPage: React.FC = () => {
setBindingPendingKey(`activate:${revisionId}`);
setBindingNotice(null);
try {
const result = await runtimeGAgentApi.activateScopeBindingRevision(
const result = await runtimeGAgentApi.activateMemberBindingRevision(
normalizedScopeId,
revisionId,
);
Expand Down Expand Up @@ -1149,7 +1149,7 @@ const GAgentsPage: React.FC = () => {
setBindingPendingKey(`retire:${revisionId}`);
setBindingNotice(null);
try {
const result = await runtimeGAgentApi.retireScopeBindingRevision(
const result = await runtimeGAgentApi.retireMemberBindingRevision(
normalizedScopeId,
revisionId,
);
Expand Down
12 changes: 12 additions & 0 deletions apps/aevatar-console-web/src/pages/scopes/assets.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,18 @@ jest.mock('@/shared/studio/api', () => ({
: 'actor://scope-a/default',
revisions: [],
})),
getDefaultRouteTarget: jest.fn(async (scopeId: string) => ({
available: true,
scopeId: scopeId?.trim() || 'scope-a',
serviceId: scopeId?.trim() === 'scope-b' ? 'ops' : 'default',
displayName: scopeId?.trim() === 'scope-b' ? 'Workspace Beta' : 'Workspace Demo',
serviceKey: scopeId?.trim() === 'scope-b' ? 'scope-b:ops' : 'scope-a:default',
primaryActorId:
scopeId?.trim() === 'scope-b'
? 'actor://scope-b/ops'
: 'actor://scope-a/default',
revisions: [],
})),
},
}));

Expand Down
Loading
Loading