@stigmer/react 3.5.3 → 3.7.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/agent/AgentPicker.d.ts +10 -1
- package/agent/AgentPicker.d.ts.map +1 -1
- package/agent/AgentPicker.js +2 -2
- package/agent/AgentPicker.js.map +1 -1
- package/billing/CreditLedgerTable.d.ts.map +1 -1
- package/billing/CreditLedgerTable.js +2 -7
- package/billing/CreditLedgerTable.js.map +1 -1
- package/channel/AgentChannelsPanel.d.ts.map +1 -1
- package/channel/AgentChannelsPanel.js +22 -5
- package/channel/AgentChannelsPanel.js.map +1 -1
- package/channel/ChannelTemplatesDialog.d.ts +53 -0
- package/channel/ChannelTemplatesDialog.d.ts.map +1 -0
- package/channel/ChannelTemplatesDialog.js +150 -0
- package/channel/ChannelTemplatesDialog.js.map +1 -0
- package/channel/index.d.ts +8 -0
- package/channel/index.d.ts.map +1 -1
- package/channel/index.js +4 -0
- package/channel/index.js.map +1 -1
- package/channel/providers.d.ts +12 -0
- package/channel/providers.d.ts.map +1 -1
- package/channel/providers.js +14 -2
- package/channel/providers.js.map +1 -1
- package/channel/templatePresentation.d.ts +37 -0
- package/channel/templatePresentation.d.ts.map +1 -0
- package/channel/templatePresentation.js +69 -0
- package/channel/templatePresentation.js.map +1 -0
- package/channel/useChannelTemplateList.d.ts +64 -0
- package/channel/useChannelTemplateList.d.ts.map +1 -0
- package/channel/useChannelTemplateList.js +69 -0
- package/channel/useChannelTemplateList.js.map +1 -0
- package/channel/useChannelTemplateReadiness.d.ts +53 -0
- package/channel/useChannelTemplateReadiness.d.ts.map +1 -0
- package/channel/useChannelTemplateReadiness.js +42 -0
- package/channel/useChannelTemplateReadiness.js.map +1 -0
- package/composer/ComposerToolbar.d.ts +6 -1
- package/composer/ComposerToolbar.d.ts.map +1 -1
- package/composer/ComposerToolbar.js +2 -2
- package/composer/ComposerToolbar.js.map +1 -1
- package/composer/SessionComposer.d.ts +9 -0
- package/composer/SessionComposer.d.ts.map +1 -1
- package/composer/SessionComposer.js +13 -2
- package/composer/SessionComposer.js.map +1 -1
- package/dashboard/useDashboardFailedRuns.d.ts.map +1 -1
- package/dashboard/useDashboardFailedRuns.js +2 -0
- package/dashboard/useDashboardFailedRuns.js.map +1 -1
- package/execution/useCreateAgentExecution.d.ts +14 -0
- package/execution/useCreateAgentExecution.d.ts.map +1 -1
- package/execution/useCreateAgentExecution.js +5 -0
- package/execution/useCreateAgentExecution.js.map +1 -1
- package/index.d.ts +4 -2
- package/index.d.ts.map +1 -1
- package/index.js +10 -1
- package/index.js.map +1 -1
- package/internal/Pagination.d.ts +15 -0
- package/internal/Pagination.d.ts.map +1 -0
- package/internal/Pagination.js +20 -0
- package/internal/Pagination.js.map +1 -0
- package/library/useExportResource.d.ts +4 -3
- package/library/useExportResource.d.ts.map +1 -1
- package/library/useExportResource.js +1 -1
- package/library/useExportResource.js.map +1 -1
- package/models/ModelSelector.d.ts +26 -1
- package/models/ModelSelector.d.ts.map +1 -1
- package/models/ModelSelector.js +27 -6
- package/models/ModelSelector.js.map +1 -1
- package/models/index.d.ts +2 -0
- package/models/index.d.ts.map +1 -1
- package/models/index.js +1 -0
- package/models/index.js.map +1 -1
- package/models/registry.d.ts +10 -0
- package/models/registry.d.ts.map +1 -1
- package/models/registry.js +3 -0
- package/models/registry.js.map +1 -1
- package/models/service-tier.d.ts +27 -0
- package/models/service-tier.d.ts.map +1 -0
- package/models/service-tier.js +34 -0
- package/models/service-tier.js.map +1 -0
- package/organization/OrgProvider.d.ts +11 -4
- package/organization/OrgProvider.d.ts.map +1 -1
- package/organization/OrgProvider.js +28 -4
- package/organization/OrgProvider.js.map +1 -1
- package/package.json +4 -4
- package/resource-detail/useDeleteResource.d.ts +1 -1
- package/resource-detail/useDeleteResource.d.ts.map +1 -1
- package/resource-detail/useDeleteResource.js +5 -0
- package/resource-detail/useDeleteResource.js.map +1 -1
- package/resource-workbench/components/ResourceWorkbench.d.ts +10 -1
- package/resource-workbench/components/ResourceWorkbench.d.ts.map +1 -1
- package/resource-workbench/components/ResourceWorkbench.js +6 -2
- package/resource-workbench/components/ResourceWorkbench.js.map +1 -1
- package/resource-workbench/hooks/useResourceCollection.d.ts +8 -0
- package/resource-workbench/hooks/useResourceCollection.d.ts.map +1 -1
- package/resource-workbench/hooks/useResourceCollection.js +2 -2
- package/resource-workbench/hooks/useResourceCollection.js.map +1 -1
- package/schedule/CadenceField.d.ts +31 -0
- package/schedule/CadenceField.d.ts.map +1 -0
- package/schedule/CadenceField.js +116 -0
- package/schedule/CadenceField.js.map +1 -0
- package/schedule/ScheduleDetailView.d.ts +81 -0
- package/schedule/ScheduleDetailView.d.ts.map +1 -0
- package/schedule/ScheduleDetailView.js +648 -0
- package/schedule/ScheduleDetailView.js.map +1 -0
- package/schedule/ScheduleForm.d.ts +46 -0
- package/schedule/ScheduleForm.d.ts.map +1 -0
- package/schedule/ScheduleForm.js +214 -0
- package/schedule/ScheduleForm.js.map +1 -0
- package/schedule/ScheduleRowActions.d.ts +20 -0
- package/schedule/ScheduleRowActions.d.ts.map +1 -0
- package/schedule/ScheduleRowActions.js +54 -0
- package/schedule/ScheduleRowActions.js.map +1 -0
- package/schedule/ScheduleRunsTable.d.ts +72 -0
- package/schedule/ScheduleRunsTable.d.ts.map +1 -0
- package/schedule/ScheduleRunsTable.js +161 -0
- package/schedule/ScheduleRunsTable.js.map +1 -0
- package/schedule/TimeZoneField.d.ts +32 -0
- package/schedule/TimeZoneField.d.ts.map +1 -0
- package/schedule/TimeZoneField.js +104 -0
- package/schedule/TimeZoneField.js.map +1 -0
- package/schedule/cadence.d.ts +95 -0
- package/schedule/cadence.d.ts.map +1 -0
- package/schedule/cadence.js +242 -0
- package/schedule/cadence.js.map +1 -0
- package/schedule/index.d.ts +37 -0
- package/schedule/index.d.ts.map +1 -0
- package/schedule/index.js +19 -0
- package/schedule/index.js.map +1 -0
- package/schedule/scheduleColumns.d.ts +26 -0
- package/schedule/scheduleColumns.d.ts.map +1 -0
- package/schedule/scheduleColumns.js +77 -0
- package/schedule/scheduleColumns.js.map +1 -0
- package/schedule/scheduleListFn.d.ts +50 -0
- package/schedule/scheduleListFn.d.ts.map +1 -0
- package/schedule/scheduleListFn.js +65 -0
- package/schedule/scheduleListFn.js.map +1 -0
- package/schedule/scheduleState.d.ts +43 -0
- package/schedule/scheduleState.d.ts.map +1 -0
- package/schedule/scheduleState.js +67 -0
- package/schedule/scheduleState.js.map +1 -0
- package/schedule/useCreateSchedule.d.ts +57 -0
- package/schedule/useCreateSchedule.d.ts.map +1 -0
- package/schedule/useCreateSchedule.js +61 -0
- package/schedule/useCreateSchedule.js.map +1 -0
- package/schedule/useResumeSchedule.d.ts +30 -0
- package/schedule/useResumeSchedule.d.ts.map +1 -0
- package/schedule/useResumeSchedule.js +45 -0
- package/schedule/useResumeSchedule.js.map +1 -0
- package/schedule/useSchedule.d.ts +39 -0
- package/schedule/useSchedule.d.ts.map +1 -0
- package/schedule/useSchedule.js +44 -0
- package/schedule/useSchedule.js.map +1 -0
- package/schedule/useScheduleCount.d.ts +38 -0
- package/schedule/useScheduleCount.d.ts.map +1 -0
- package/schedule/useScheduleCount.js +30 -0
- package/schedule/useScheduleCount.js.map +1 -0
- package/schedule/useScheduleList.d.ts +48 -0
- package/schedule/useScheduleList.d.ts.map +1 -0
- package/schedule/useScheduleList.js +43 -0
- package/schedule/useScheduleList.js.map +1 -0
- package/schedule/useScheduleRuns.d.ts +44 -0
- package/schedule/useScheduleRuns.d.ts.map +1 -0
- package/schedule/useScheduleRuns.js +48 -0
- package/schedule/useScheduleRuns.js.map +1 -0
- package/schedule/useSetScheduleEnabled.d.ts +31 -0
- package/schedule/useSetScheduleEnabled.d.ts.map +1 -0
- package/schedule/useSetScheduleEnabled.js +53 -0
- package/schedule/useSetScheduleEnabled.js.map +1 -0
- package/schedule/useTriggerSchedule.d.ts +41 -0
- package/schedule/useTriggerSchedule.d.ts.map +1 -0
- package/schedule/useTriggerSchedule.js +62 -0
- package/schedule/useTriggerSchedule.js.map +1 -0
- package/schedule/useUpdateScheduleSpec.d.ts +49 -0
- package/schedule/useUpdateScheduleSpec.d.ts.map +1 -0
- package/schedule/useUpdateScheduleSpec.js +70 -0
- package/schedule/useUpdateScheduleSpec.js.map +1 -0
- package/search/useResourceCount.d.ts +2 -1
- package/search/useResourceCount.d.ts.map +1 -1
- package/search/useResourceCount.js +6 -1
- package/search/useResourceCount.js.map +1 -1
- package/session/useNewSessionFlow.d.ts.map +1 -1
- package/session/useNewSessionFlow.js +1 -0
- package/session/useNewSessionFlow.js.map +1 -1
- package/session/useSessionConversation.d.ts +11 -0
- package/session/useSessionConversation.d.ts.map +1 -1
- package/session/useSessionConversation.js +1 -0
- package/session/useSessionConversation.js.map +1 -1
- package/session/useSessionPageFlow.d.ts.map +1 -1
- package/session/useSessionPageFlow.js +1 -0
- package/session/useSessionPageFlow.js.map +1 -1
- package/src/agent/AgentPicker.tsx +13 -1
- package/src/billing/CreditLedgerTable.tsx +3 -42
- package/src/channel/AgentChannelsPanel.tsx +43 -1
- package/src/channel/ChannelTemplatesDialog.tsx +433 -0
- package/src/channel/__tests__/AgentChannelsPanel.test.tsx +73 -0
- package/src/channel/__tests__/ChannelTemplatesDialog.test.tsx +292 -0
- package/src/channel/__tests__/providers.test.ts +9 -0
- package/src/channel/__tests__/templatePresentation.test.ts +96 -0
- package/src/channel/__tests__/useChannelTemplateList.test.tsx +216 -0
- package/src/channel/__tests__/useChannelTemplateReadiness.test.tsx +124 -0
- package/src/channel/index.ts +15 -0
- package/src/channel/providers.ts +26 -2
- package/src/channel/templatePresentation.ts +82 -0
- package/src/channel/useChannelTemplateList.ts +123 -0
- package/src/channel/useChannelTemplateReadiness.ts +69 -0
- package/src/composer/ComposerToolbar.tsx +9 -0
- package/src/composer/SessionComposer.tsx +24 -1
- package/src/composer/__tests__/SessionComposer-serviceTier.test.tsx +156 -0
- package/src/dashboard/__tests__/useDashboardFailedRuns.test.tsx +106 -0
- package/src/dashboard/useDashboardFailedRuns.ts +2 -0
- package/src/execution/useCreateAgentExecution.ts +18 -0
- package/src/index.ts +70 -0
- package/src/internal/Pagination.tsx +72 -0
- package/src/library/useExportResource.ts +4 -3
- package/src/models/ModelSelector.tsx +100 -3
- package/src/models/__tests__/ModelSelector-serviceTier.test.tsx +172 -0
- package/src/models/__tests__/useModelRegistry.test.tsx +15 -0
- package/src/models/index.ts +2 -0
- package/src/models/registry.ts +16 -0
- package/src/models/service-tier.ts +49 -0
- package/src/organization/OrgProvider.tsx +29 -4
- package/src/organization/__tests__/OrgProvider.orgSwitch.test.tsx +89 -0
- package/src/resource-detail/useDeleteResource.ts +11 -1
- package/src/resource-workbench/__tests__/ResourceWorkbench.test.tsx +112 -0
- package/src/resource-workbench/components/ResourceWorkbench.tsx +32 -15
- package/src/resource-workbench/hooks/useResourceCollection.ts +11 -1
- package/src/schedule/CadenceField.tsx +365 -0
- package/src/schedule/ScheduleDetailView.tsx +1651 -0
- package/src/schedule/ScheduleForm.tsx +615 -0
- package/src/schedule/ScheduleRowActions.tsx +124 -0
- package/src/schedule/ScheduleRunsTable.tsx +424 -0
- package/src/schedule/TimeZoneField.tsx +199 -0
- package/src/schedule/__tests__/ScheduleDetailView.test.tsx +683 -0
- package/src/schedule/__tests__/cadence.test.ts +278 -0
- package/src/schedule/__tests__/scheduleColumnsRowActions.test.tsx +176 -0
- package/src/schedule/__tests__/scheduleCreation.test.tsx +537 -0
- package/src/schedule/__tests__/scheduleHooks.test.tsx +399 -0
- package/src/schedule/__tests__/scheduleListFn.test.ts +128 -0
- package/src/schedule/__tests__/scheduleState.test.ts +133 -0
- package/src/schedule/cadence.ts +298 -0
- package/src/schedule/index.ts +69 -0
- package/src/schedule/scheduleColumns.tsx +118 -0
- package/src/schedule/scheduleListFn.ts +108 -0
- package/src/schedule/scheduleState.ts +96 -0
- package/src/schedule/useCreateSchedule.ts +88 -0
- package/src/schedule/useResumeSchedule.ts +67 -0
- package/src/schedule/useSchedule.ts +67 -0
- package/src/schedule/useScheduleCount.ts +57 -0
- package/src/schedule/useScheduleList.ts +83 -0
- package/src/schedule/useScheduleRuns.ts +93 -0
- package/src/schedule/useSetScheduleEnabled.ts +84 -0
- package/src/schedule/useTriggerSchedule.ts +90 -0
- package/src/schedule/useUpdateScheduleSpec.ts +108 -0
- package/src/search/__tests__/useResourceCount.test.tsx +89 -0
- package/src/search/useResourceCount.ts +8 -2
- package/src/session/useNewSessionFlow.ts +1 -0
- package/src/session/useSessionConversation.ts +12 -0
- package/src/session/useSessionPageFlow.ts +1 -0
- package/src/workflow/WorkflowDashboard.tsx +1 -0
- package/src/workflow/__tests__/inspector-forms.test.tsx +119 -2
- package/src/workflow/inspector/forms/AgentCallForm.tsx +260 -37
- package/src/workflow/inspector/tabs/RuntimeTab.tsx +72 -33
- package/src/workflow/starter-workflow-yaml.ts +2 -1
- package/src/workflow/useWorkflowExecutionList.ts +13 -2
- package/styles.css +1 -1
- package/workflow/CanvasTransitionEdge.d.ts +1 -1
- package/workflow/WorkflowDashboard.d.ts.map +1 -1
- package/workflow/WorkflowDashboard.js +1 -0
- package/workflow/WorkflowDashboard.js.map +1 -1
- package/workflow/inspector/forms/AgentCallForm.d.ts +18 -2
- package/workflow/inspector/forms/AgentCallForm.d.ts.map +1 -1
- package/workflow/inspector/forms/AgentCallForm.js +87 -9
- package/workflow/inspector/forms/AgentCallForm.js.map +1 -1
- package/workflow/inspector/tabs/RuntimeTab.d.ts +2 -1
- package/workflow/inspector/tabs/RuntimeTab.d.ts.map +1 -1
- package/workflow/inspector/tabs/RuntimeTab.js +31 -5
- package/workflow/inspector/tabs/RuntimeTab.js.map +1 -1
- package/workflow/starter-workflow-yaml.d.ts +1 -1
- package/workflow/starter-workflow-yaml.d.ts.map +1 -1
- package/workflow/starter-workflow-yaml.js +2 -1
- package/workflow/starter-workflow-yaml.js.map +1 -1
- package/workflow/useWorkflowExecutionList.d.ts +10 -0
- package/workflow/useWorkflowExecutionList.d.ts.map +1 -1
- package/workflow/useWorkflowExecutionList.js +3 -2
- package/workflow/useWorkflowExecutionList.js.map +1 -1
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useCallback, useMemo, useState } from "react";
|
|
4
|
+
import { clone } from "@bufbuild/protobuf";
|
|
5
|
+
import {
|
|
6
|
+
ScheduleSchema,
|
|
7
|
+
type Schedule,
|
|
8
|
+
} from "@stigmer/protos/ai/stigmer/agentic/schedule/v1/api_pb";
|
|
9
|
+
import type { ScheduleSpec } from "@stigmer/protos/ai/stigmer/agentic/schedule/v1/spec_pb";
|
|
10
|
+
import { getUserMessage, manifestDocumentForResource } from "@stigmer/sdk";
|
|
11
|
+
import { useStigmer } from "../hooks.js";
|
|
12
|
+
import { toast } from "../feedback/toast.js";
|
|
13
|
+
|
|
14
|
+
/** Return value of {@link useUpdateScheduleSpec}. */
|
|
15
|
+
export interface UseUpdateScheduleSpecReturn {
|
|
16
|
+
/**
|
|
17
|
+
* Apply one spec mutation to the schedule. Takes the full fetched
|
|
18
|
+
* schedule (not just an id) because the write re-applies the whole
|
|
19
|
+
* resource. Resolves with the post-apply schedule; the caller
|
|
20
|
+
* refetches or replaces its local copy from it.
|
|
21
|
+
*/
|
|
22
|
+
readonly updateSpec: (
|
|
23
|
+
schedule: Schedule,
|
|
24
|
+
mutate: (spec: ScheduleSpec) => void,
|
|
25
|
+
) => Promise<Schedule>;
|
|
26
|
+
/** `true` while the apply is in flight. */
|
|
27
|
+
readonly isUpdating: boolean;
|
|
28
|
+
/** Error from the last failed apply, or `null` when healthy. */
|
|
29
|
+
readonly error: Error | null;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Behavior hook behind the schedule detail view's inline editing: apply
|
|
34
|
+
* a single spec mutation losslessly.
|
|
35
|
+
*
|
|
36
|
+
* The write path is deliberate, and it is NOT the agent detail view's
|
|
37
|
+
* input-based one: clone the fetched proto, let the caller mutate the
|
|
38
|
+
* spec in place, and re-apply the WHOLE resource through the manifest
|
|
39
|
+
* engine (`stigmer.manifest.apply`) — never down-convert to the curated
|
|
40
|
+
* `ScheduleInput` shape. The server replaces spec and mutable metadata
|
|
41
|
+
* wholesale on update, and `ScheduleInput` cannot express every
|
|
42
|
+
* metadata field (tags, description), so the input route would silently
|
|
43
|
+
* wipe them. The full-proto route is lossless by construction; the
|
|
44
|
+
* server ignores client-provided status, and re-applying never clears a
|
|
45
|
+
* platform pause (Resume is the one clearing path — see
|
|
46
|
+
* `useResumeSchedule`). Same mechanics as {@link useSetScheduleEnabled},
|
|
47
|
+
* generalized from one hardcoded field to any spec edit.
|
|
48
|
+
*
|
|
49
|
+
* Errors are NOT toasted here: inline editors surface the server's
|
|
50
|
+
* message next to the field that was edited (DD-006), and a toast on
|
|
51
|
+
* top would say the same thing twice.
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```tsx
|
|
55
|
+
* const { updateSpec, isUpdating } = useUpdateScheduleSpec();
|
|
56
|
+
*
|
|
57
|
+
* await updateSpec(schedule, (spec) => {
|
|
58
|
+
* spec.cron = "0 9 * * 1-5";
|
|
59
|
+
* spec.timeZone = "Asia/Kolkata";
|
|
60
|
+
* });
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
export function useUpdateScheduleSpec(): UseUpdateScheduleSpecReturn {
|
|
64
|
+
const stigmer = useStigmer();
|
|
65
|
+
const [isUpdating, setIsUpdating] = useState(false);
|
|
66
|
+
const [error, setError] = useState<Error | null>(null);
|
|
67
|
+
|
|
68
|
+
const updateSpec = useCallback(
|
|
69
|
+
async (
|
|
70
|
+
schedule: Schedule,
|
|
71
|
+
mutate: (spec: ScheduleSpec) => void,
|
|
72
|
+
): Promise<Schedule> => {
|
|
73
|
+
if (!schedule.spec) {
|
|
74
|
+
throw new Error(
|
|
75
|
+
"Cannot edit this schedule: it has no spec. Pass a schedule " +
|
|
76
|
+
"as returned by the server (get/getByReference).",
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
setIsUpdating(true);
|
|
81
|
+
setError(null);
|
|
82
|
+
try {
|
|
83
|
+
const updated = clone(ScheduleSchema, schedule);
|
|
84
|
+
mutate(updated.spec!);
|
|
85
|
+
|
|
86
|
+
const applied = await stigmer.manifest.apply(
|
|
87
|
+
manifestDocumentForResource(updated),
|
|
88
|
+
);
|
|
89
|
+
toast.success("Schedule updated");
|
|
90
|
+
return applied.message as Schedule;
|
|
91
|
+
} catch (err) {
|
|
92
|
+
// Rethrow with the user-facing message: the inline editors render
|
|
93
|
+
// `message` verbatim next to the edited field.
|
|
94
|
+
const wrapped = new Error(getUserMessage(err));
|
|
95
|
+
setError(wrapped);
|
|
96
|
+
throw wrapped;
|
|
97
|
+
} finally {
|
|
98
|
+
setIsUpdating(false);
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
[stigmer],
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
return useMemo(
|
|
105
|
+
() => ({ updateSpec, isUpdating, error }),
|
|
106
|
+
[updateSpec, isUpdating, error],
|
|
107
|
+
);
|
|
108
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from "vitest";
|
|
2
|
+
import { renderHook, waitFor } from "@testing-library/react";
|
|
3
|
+
import type { ListParams, ListResult } from "@stigmer/sdk";
|
|
4
|
+
import { useResourceCount } from "../useResourceCount";
|
|
5
|
+
|
|
6
|
+
function mockListFn(totalCount = 0) {
|
|
7
|
+
return vi.fn<(params: ListParams) => Promise<ListResult>>().mockResolvedValue({
|
|
8
|
+
entries: [],
|
|
9
|
+
totalCount,
|
|
10
|
+
totalPages: totalCount > 0 ? 1 : 0,
|
|
11
|
+
} as never);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
describe("useResourceCount", () => {
|
|
15
|
+
it("counts in org scope by default: org sent, crossOrgPublic false", async () => {
|
|
16
|
+
const listFn = mockListFn(7);
|
|
17
|
+
|
|
18
|
+
const { result } = renderHook(() => useResourceCount(listFn, "acme"));
|
|
19
|
+
|
|
20
|
+
await waitFor(() => expect(result.current.isLoading).toBe(false));
|
|
21
|
+
|
|
22
|
+
expect(result.current.count).toBe(7);
|
|
23
|
+
const params = listFn.mock.calls[0][0];
|
|
24
|
+
expect(params.org).toBe("acme");
|
|
25
|
+
expect(params.crossOrgPublic).toBe(false);
|
|
26
|
+
expect(params.page).toEqual({ num: 1, size: 1 });
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('always sends org in "all" scope (empty org means a cross-org FGA dump to the backend)', async () => {
|
|
30
|
+
const listFn = mockListFn(3);
|
|
31
|
+
|
|
32
|
+
const { result } = renderHook(() =>
|
|
33
|
+
useResourceCount(listFn, "acme", { scope: "all" }),
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
await waitFor(() => expect(result.current.isLoading).toBe(false));
|
|
37
|
+
|
|
38
|
+
const params = listFn.mock.calls[0][0];
|
|
39
|
+
// Regression guard: the pre-fix hook blanked org for "all", which the
|
|
40
|
+
// search backend defines as "every org the caller can access" — the
|
|
41
|
+
// Library cards then counted platform-wide instead of org + public.
|
|
42
|
+
expect(params.org).toBe("acme");
|
|
43
|
+
expect(params.crossOrgPublic).toBe(true);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it("does not fetch when org is null", async () => {
|
|
47
|
+
const listFn = mockListFn();
|
|
48
|
+
|
|
49
|
+
const { result } = renderHook(() => useResourceCount(listFn, null));
|
|
50
|
+
|
|
51
|
+
await waitFor(() => expect(result.current.isLoading).toBe(false));
|
|
52
|
+
|
|
53
|
+
expect(listFn).not.toHaveBeenCalled();
|
|
54
|
+
expect(result.current.count).toBeUndefined();
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it("recounts when refetchToken changes", async () => {
|
|
58
|
+
const listFn = mockListFn(1);
|
|
59
|
+
|
|
60
|
+
const { result, rerender } = renderHook(
|
|
61
|
+
({ token }: { token: number }) =>
|
|
62
|
+
useResourceCount(listFn, "acme", { refetchToken: token }),
|
|
63
|
+
{ initialProps: { token: 0 } },
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
await waitFor(() => expect(result.current.isLoading).toBe(false));
|
|
67
|
+
expect(listFn).toHaveBeenCalledTimes(1);
|
|
68
|
+
|
|
69
|
+
rerender({ token: 1 });
|
|
70
|
+
|
|
71
|
+
await waitFor(() => expect(listFn).toHaveBeenCalledTimes(2));
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it("refetches with the new org when the org changes", async () => {
|
|
75
|
+
const listFn = mockListFn(2);
|
|
76
|
+
|
|
77
|
+
const { result, rerender } = renderHook(
|
|
78
|
+
({ org }: { org: string }) => useResourceCount(listFn, org),
|
|
79
|
+
{ initialProps: { org: "acme" } },
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
await waitFor(() => expect(result.current.isLoading).toBe(false));
|
|
83
|
+
|
|
84
|
+
rerender({ org: "globex" });
|
|
85
|
+
|
|
86
|
+
await waitFor(() => expect(listFn).toHaveBeenCalledTimes(2));
|
|
87
|
+
expect(listFn.mock.calls[1][0].org).toBe("globex");
|
|
88
|
+
});
|
|
89
|
+
});
|
|
@@ -11,7 +11,8 @@ export interface UseResourceCountOptions {
|
|
|
11
11
|
* Controls resource visibility scope.
|
|
12
12
|
*
|
|
13
13
|
* - `"org"` — all resources owned by the given organization, regardless of visibility.
|
|
14
|
-
* - `"all"` — all resources
|
|
14
|
+
* - `"all"` — all resources owned by the given organization plus public resources
|
|
15
|
+
* from other organizations.
|
|
15
16
|
*
|
|
16
17
|
* @default "org"
|
|
17
18
|
*/
|
|
@@ -64,10 +65,15 @@ export function useResourceCount(
|
|
|
64
65
|
const { data: count, isLoading, isRefetching, error, refetch } = useFetch<number | undefined>(
|
|
65
66
|
org
|
|
66
67
|
? async () => {
|
|
68
|
+
// Identical params to useResourceList so a card's count always matches
|
|
69
|
+
// the list page it links to. `org` is ALWAYS sent: an empty org means
|
|
70
|
+
// "every org the caller can access" to the search backend (a global FGA
|
|
71
|
+
// dump), and `crossOrgPublic` with an empty org matches zero rows.
|
|
67
72
|
const params: ListParams = {
|
|
68
|
-
org
|
|
73
|
+
org,
|
|
69
74
|
query: query || undefined,
|
|
70
75
|
excludePublic: false,
|
|
76
|
+
crossOrgPublic: scope === "all",
|
|
71
77
|
page: { num: 1, size: 1 },
|
|
72
78
|
};
|
|
73
79
|
const result = await listFn(params);
|
|
@@ -17,6 +17,7 @@ import type {
|
|
|
17
17
|
WorkspaceEntryInput,
|
|
18
18
|
} from "@stigmer/sdk";
|
|
19
19
|
import { isTerminalPhase } from "../execution/execution-phases.js";
|
|
20
|
+
import type { ServiceTierOption } from "../models/service-tier.js";
|
|
20
21
|
import { useStigmer } from "../hooks.js";
|
|
21
22
|
import { toError } from "../internal/toError.js";
|
|
22
23
|
import { useConversationStoreRef } from "../internal/store/index.js";
|
|
@@ -96,6 +97,16 @@ export interface SendFollowUpOptions {
|
|
|
96
97
|
* - `"plan"`: read-only analysis, no file mutations.
|
|
97
98
|
*/
|
|
98
99
|
readonly interactionMode?: "agent" | "plan";
|
|
100
|
+
/**
|
|
101
|
+
* Service tier for this execution's model calls (stigmer/stigmer#357).
|
|
102
|
+
*
|
|
103
|
+
* Only set when the user actively selected `"fast"`; `undefined` preserves
|
|
104
|
+
* the unspecified-vs-explicit distinction (unset resolves to standard on
|
|
105
|
+
* the platform side — never the provider account default).
|
|
106
|
+
*
|
|
107
|
+
* @see {@link CreateAgentExecutionInput.serviceTier}
|
|
108
|
+
*/
|
|
109
|
+
readonly serviceTier?: ServiceTierOption;
|
|
99
110
|
/**
|
|
100
111
|
* Marks this execution as a Build-from-plan turn.
|
|
101
112
|
*
|
|
@@ -642,6 +653,7 @@ export function useSessionConversation(
|
|
|
642
653
|
runtimeEnv: options?.runtimeEnv,
|
|
643
654
|
attachments: options?.attachments,
|
|
644
655
|
interactionMode: options?.interactionMode,
|
|
656
|
+
serviceTier: options?.serviceTier,
|
|
645
657
|
buildFromPlan: options?.buildFromPlan,
|
|
646
658
|
autoApproveAll: options?.autoApproveAll,
|
|
647
659
|
workspaceFileRefs: options?.workspaceFileRefs,
|
|
@@ -438,6 +438,7 @@ export function useSessionPageFlow(
|
|
|
438
438
|
runtimeEnv,
|
|
439
439
|
attachments: context?.attachments,
|
|
440
440
|
interactionMode: context?.interactionMode,
|
|
441
|
+
serviceTier: context?.serviceTier,
|
|
441
442
|
buildFromPlan: context?.buildFromPlan,
|
|
442
443
|
// Sourced from the session-scoped preference set at the approval gate,
|
|
443
444
|
// not from the composer (the pre-arm toggle was removed).
|
|
@@ -34,15 +34,132 @@ describe("AgentCallForm", () => {
|
|
|
34
34
|
expect(textarea.value).toBe("Hello world");
|
|
35
35
|
});
|
|
36
36
|
|
|
37
|
-
it("renders model input from
|
|
37
|
+
it("renders model input from the run_config block", () => {
|
|
38
38
|
const node = makeNode(WorkflowTaskKind.agent_call, {
|
|
39
39
|
agent: "x",
|
|
40
40
|
message: "y",
|
|
41
|
-
|
|
41
|
+
run_config: { model_name: "claude-sonnet-4", max_cost_usd: 0.5 },
|
|
42
42
|
});
|
|
43
43
|
render(<AgentCallForm node={node} onFieldChange={vi.fn()} />);
|
|
44
44
|
const input = screen.getByTestId("agent-call-model-input") as HTMLInputElement;
|
|
45
45
|
expect(input.value).toBe("claude-sonnet-4");
|
|
46
|
+
const budget = screen.getByTestId("agent-call-budget-input") as HTMLInputElement;
|
|
47
|
+
expect(budget.value).toBe("0.5");
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it("emits an undefined run_config when the last field is cleared", () => {
|
|
51
|
+
const onFieldChange = vi.fn();
|
|
52
|
+
const node = makeNode(WorkflowTaskKind.agent_call, {
|
|
53
|
+
agent: "x",
|
|
54
|
+
message: "y",
|
|
55
|
+
run_config: { max_cost_usd: 0.5 },
|
|
56
|
+
});
|
|
57
|
+
render(<AgentCallForm node={node} onFieldChange={onFieldChange} />);
|
|
58
|
+
|
|
59
|
+
const budget = screen.getByTestId("agent-call-budget-input") as HTMLInputElement;
|
|
60
|
+
fireEvent.change(budget, { target: { value: "" } });
|
|
61
|
+
|
|
62
|
+
// Empty means omit: a blank field must not persist a zero override.
|
|
63
|
+
expect(onFieldChange).toHaveBeenCalledWith("run_config", undefined);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("writes budget changes into run_config.max_cost_usd", () => {
|
|
67
|
+
const onFieldChange = vi.fn();
|
|
68
|
+
const node = makeNode(WorkflowTaskKind.agent_call, {
|
|
69
|
+
agent: "x",
|
|
70
|
+
message: "y",
|
|
71
|
+
run_config: { model_name: "claude-sonnet-4" },
|
|
72
|
+
});
|
|
73
|
+
render(<AgentCallForm node={node} onFieldChange={onFieldChange} />);
|
|
74
|
+
|
|
75
|
+
const budget = screen.getByTestId("agent-call-budget-input") as HTMLInputElement;
|
|
76
|
+
fireEvent.change(budget, { target: { value: "1.25" } });
|
|
77
|
+
|
|
78
|
+
expect(onFieldChange).toHaveBeenCalledWith("run_config", {
|
|
79
|
+
model_name: "claude-sonnet-4",
|
|
80
|
+
max_cost_usd: 1.25,
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it("renders workspace entries and edits the git url in place", () => {
|
|
85
|
+
const onFieldChange = vi.fn();
|
|
86
|
+
const node = makeNode(WorkflowTaskKind.agent_call, {
|
|
87
|
+
agent: "x",
|
|
88
|
+
message: "y",
|
|
89
|
+
workspace_entries: [
|
|
90
|
+
{ name: "app", source: { git_repo: { url: "https://github.com/acme/app", branch: "main" } } },
|
|
91
|
+
],
|
|
92
|
+
});
|
|
93
|
+
render(<AgentCallForm node={node} onFieldChange={onFieldChange} />);
|
|
94
|
+
|
|
95
|
+
const url = screen.getByTestId("agent-call-workspace-url-0") as HTMLInputElement;
|
|
96
|
+
expect(url.value).toBe("https://github.com/acme/app");
|
|
97
|
+
|
|
98
|
+
fireEvent.change(url, { target: { value: "https://github.com/acme/other" } });
|
|
99
|
+
expect(onFieldChange).toHaveBeenCalledWith("workspace_entries", [
|
|
100
|
+
{ name: "app", source: { git_repo: { url: "https://github.com/acme/other", branch: "main" } } },
|
|
101
|
+
]);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it("adds a workspace entry row", () => {
|
|
105
|
+
const onFieldChange = vi.fn();
|
|
106
|
+
const node = makeNode(WorkflowTaskKind.agent_call, { agent: "x", message: "y" });
|
|
107
|
+
render(<AgentCallForm node={node} onFieldChange={onFieldChange} />);
|
|
108
|
+
|
|
109
|
+
fireEvent.click(screen.getByTestId("agent-call-workspace-add"));
|
|
110
|
+
expect(onFieldChange).toHaveBeenCalledWith("workspace_entries", [
|
|
111
|
+
{ source: { git_repo: { url: "" } } },
|
|
112
|
+
]);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it("emits undefined when the last workspace entry is removed", () => {
|
|
116
|
+
const onFieldChange = vi.fn();
|
|
117
|
+
const node = makeNode(WorkflowTaskKind.agent_call, {
|
|
118
|
+
agent: "x",
|
|
119
|
+
message: "y",
|
|
120
|
+
workspace_entries: [
|
|
121
|
+
{ source: { git_repo: { url: "https://github.com/acme/app" } } },
|
|
122
|
+
],
|
|
123
|
+
});
|
|
124
|
+
render(<AgentCallForm node={node} onFieldChange={onFieldChange} />);
|
|
125
|
+
|
|
126
|
+
fireEvent.click(screen.getByLabelText("Remove workspace entry 1"));
|
|
127
|
+
expect(onFieldChange).toHaveBeenCalledWith("workspace_entries", undefined);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it("edits environment references as org/slug rows with empty-org omitted", () => {
|
|
131
|
+
const onFieldChange = vi.fn();
|
|
132
|
+
const node = makeNode(WorkflowTaskKind.agent_call, {
|
|
133
|
+
agent: "x",
|
|
134
|
+
message: "y",
|
|
135
|
+
environment_refs: [{ slug: "shared-secrets" }],
|
|
136
|
+
});
|
|
137
|
+
render(<AgentCallForm node={node} onFieldChange={onFieldChange} />);
|
|
138
|
+
|
|
139
|
+
const slug = screen.getByTestId("agent-call-envref-slug-0") as HTMLInputElement;
|
|
140
|
+
expect(slug.value).toBe("shared-secrets");
|
|
141
|
+
|
|
142
|
+
fireEvent.change(slug, { target: { value: "other-secrets" } });
|
|
143
|
+
// Empty org stays omitted — an empty string must not become a stored
|
|
144
|
+
// org override (relative refs resolve to the workflow's own org).
|
|
145
|
+
expect(onFieldChange).toHaveBeenCalledWith("environment_refs", [
|
|
146
|
+
{ slug: "other-secrets" },
|
|
147
|
+
]);
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it("adds and removes environment reference rows", () => {
|
|
151
|
+
const onFieldChange = vi.fn();
|
|
152
|
+
const node = makeNode(WorkflowTaskKind.agent_call, {
|
|
153
|
+
agent: "x",
|
|
154
|
+
message: "y",
|
|
155
|
+
environment_refs: [{ slug: "a" }, { org: "acme", slug: "b" }],
|
|
156
|
+
});
|
|
157
|
+
render(<AgentCallForm node={node} onFieldChange={onFieldChange} />);
|
|
158
|
+
|
|
159
|
+
fireEvent.click(screen.getByLabelText("Remove environment reference 1"));
|
|
160
|
+
expect(onFieldChange).toHaveBeenCalledWith("environment_refs", [
|
|
161
|
+
{ org: "acme", slug: "b" },
|
|
162
|
+
]);
|
|
46
163
|
});
|
|
47
164
|
|
|
48
165
|
it("shows structured output section when output is present", () => {
|