@stigmer/react 3.1.7 → 3.1.8
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/AgentDetailView.d.ts +9 -1
- package/agent/AgentDetailView.d.ts.map +1 -1
- package/agent/AgentDetailView.js +15 -4
- package/agent/AgentDetailView.js.map +1 -1
- package/environment/EnvironmentListPanel.d.ts.map +1 -1
- package/environment/EnvironmentListPanel.js +11 -3
- package/environment/EnvironmentListPanel.js.map +1 -1
- package/environment/EnvironmentVariableEditor.d.ts.map +1 -1
- package/environment/EnvironmentVariableEditor.js +9 -3
- package/environment/EnvironmentVariableEditor.js.map +1 -1
- package/environment/index.d.ts +1 -0
- package/environment/index.d.ts.map +1 -1
- package/environment/index.js +1 -0
- package/environment/index.js.map +1 -1
- package/environment/shareRestriction.d.ts +13 -0
- package/environment/shareRestriction.d.ts.map +1 -0
- package/environment/shareRestriction.js +15 -0
- package/environment/shareRestriction.js.map +1 -0
- package/execution/ToolCallItem.d.ts.map +1 -1
- package/execution/ToolCallItem.js +12 -0
- package/execution/ToolCallItem.js.map +1 -1
- package/execution/ToolRunGroup.js +4 -0
- package/execution/ToolRunGroup.js.map +1 -1
- package/execution/WriteBackCard.d.ts +14 -5
- package/execution/WriteBackCard.d.ts.map +1 -1
- package/execution/WriteBackCard.js +103 -32
- package/execution/WriteBackCard.js.map +1 -1
- package/execution/WriteBacksWidget.d.ts +1 -1
- package/execution/WriteBacksWidget.js +2 -2
- package/execution/WriteBacksWidget.js.map +1 -1
- package/execution/index.d.ts +2 -0
- package/execution/index.d.ts.map +1 -1
- package/execution/index.js +1 -0
- package/execution/index.js.map +1 -1
- package/execution/write-back-utils.d.ts +57 -0
- package/execution/write-back-utils.d.ts.map +1 -0
- package/execution/write-back-utils.js +81 -0
- package/execution/write-back-utils.js.map +1 -0
- package/index.d.ts +6 -2
- package/index.d.ts.map +1 -1
- package/index.js +6 -1
- package/index.js.map +1 -1
- package/internal/dev/dom-counter.d.ts.map +1 -1
- package/internal/dev/dom-counter.js +2 -2
- package/internal/dev/dom-counter.js.map +1 -1
- package/internal/dev/enabled.d.ts +7 -0
- package/internal/dev/enabled.d.ts.map +1 -0
- package/internal/dev/enabled.js +38 -0
- package/internal/dev/enabled.js.map +1 -0
- package/internal/dev/profiler-wrapper.d.ts +3 -3
- package/internal/dev/profiler-wrapper.d.ts.map +1 -1
- package/internal/dev/profiler-wrapper.js +5 -5
- package/internal/dev/profiler-wrapper.js.map +1 -1
- package/internal/dev/use-key-stability.d.ts.map +1 -1
- package/internal/dev/use-key-stability.js +2 -2
- package/internal/dev/use-key-stability.js.map +1 -1
- package/internal/dev/use-render-tracer.d.ts +2 -2
- package/internal/dev/use-render-tracer.d.ts.map +1 -1
- package/internal/dev/use-render-tracer.js +4 -4
- package/internal/dev/use-render-tracer.js.map +1 -1
- package/internal/dev/use-stream-rate.d.ts +2 -1
- package/internal/dev/use-stream-rate.d.ts.map +1 -1
- package/internal/dev/use-stream-rate.js +4 -3
- package/internal/dev/use-stream-rate.js.map +1 -1
- package/library/ResourceVisibilityControl.d.ts +3 -0
- package/library/ResourceVisibilityControl.d.ts.map +1 -1
- package/library/ResourceVisibilityControl.js +22 -8
- package/library/ResourceVisibilityControl.js.map +1 -1
- package/library/useUpdateVisibility.d.ts +5 -3
- package/library/useUpdateVisibility.d.ts.map +1 -1
- package/library/useUpdateVisibility.js +7 -2
- package/library/useUpdateVisibility.js.map +1 -1
- package/library/visibilityLevels.d.ts +17 -0
- package/library/visibilityLevels.d.ts.map +1 -1
- package/library/visibilityLevels.js +32 -0
- package/library/visibilityLevels.js.map +1 -1
- package/package.json +4 -4
- package/session/NewSessionViewer.d.ts +11 -1
- package/session/NewSessionViewer.d.ts.map +1 -1
- package/session/NewSessionViewer.js +28 -8
- package/session/NewSessionViewer.js.map +1 -1
- package/session/SessionViewer.d.ts +9 -2
- package/session/SessionViewer.d.ts.map +1 -1
- package/session/SessionViewer.js +26 -12
- package/session/SessionViewer.js.map +1 -1
- package/session/audience.d.ts +12 -4
- package/session/audience.d.ts.map +1 -1
- package/session/facets/ChangesTab.d.ts.map +1 -1
- package/session/facets/ChangesTab.js +3 -1
- package/session/facets/ChangesTab.js.map +1 -1
- package/session/useNewSessionFlow.d.ts +12 -0
- package/session/useNewSessionFlow.d.ts.map +1 -1
- package/session/useNewSessionFlow.js +13 -1
- package/session/useNewSessionFlow.js.map +1 -1
- package/session/useSessionPageFlow.d.ts +13 -0
- package/session/useSessionPageFlow.d.ts.map +1 -1
- package/session/useSessionPageFlow.js +7 -2
- package/session/useSessionPageFlow.js.map +1 -1
- package/sharing/ShareAgentDialog.d.ts +55 -0
- package/sharing/ShareAgentDialog.d.ts.map +1 -0
- package/sharing/ShareAgentDialog.js +393 -0
- package/sharing/ShareAgentDialog.js.map +1 -0
- package/sharing/SharedAgentChat.d.ts +84 -0
- package/sharing/SharedAgentChat.d.ts.map +1 -0
- package/sharing/SharedAgentChat.js +80 -0
- package/sharing/SharedAgentChat.js.map +1 -0
- package/sharing/index.d.ts +16 -0
- package/sharing/index.d.ts.map +1 -0
- package/sharing/index.js +11 -0
- package/sharing/index.js.map +1 -0
- package/sharing/useRotateShareLink.d.ts +42 -0
- package/sharing/useRotateShareLink.d.ts.map +1 -0
- package/sharing/useRotateShareLink.js +55 -0
- package/sharing/useRotateShareLink.js.map +1 -0
- package/sharing/useShareAgent.d.ts +68 -0
- package/sharing/useShareAgent.d.ts.map +1 -0
- package/sharing/useShareAgent.js +41 -0
- package/sharing/useShareAgent.js.map +1 -0
- package/sharing/useShareToolReadiness.d.ts +48 -0
- package/sharing/useShareToolReadiness.d.ts.map +1 -0
- package/sharing/useShareToolReadiness.js +93 -0
- package/sharing/useShareToolReadiness.js.map +1 -0
- package/sharing/useSharedAgentProfile.d.ts +84 -0
- package/sharing/useSharedAgentProfile.d.ts.map +1 -0
- package/sharing/useSharedAgentProfile.js +72 -0
- package/sharing/useSharedAgentProfile.js.map +1 -0
- package/sharing/useUpdateAgentSharing.d.ts +86 -0
- package/sharing/useUpdateAgentSharing.d.ts.map +1 -0
- package/sharing/useUpdateAgentSharing.js +81 -0
- package/sharing/useUpdateAgentSharing.js.map +1 -0
- package/src/agent/AgentDetailView.tsx +28 -3
- package/src/environment/EnvironmentListPanel.tsx +47 -18
- package/src/environment/EnvironmentVariableEditor.tsx +27 -17
- package/src/environment/__tests__/shareRestriction.test.ts +35 -0
- package/src/environment/index.ts +5 -0
- package/src/environment/shareRestriction.ts +22 -0
- package/src/execution/ToolCallItem.tsx +19 -1
- package/src/execution/ToolRunGroup.tsx +4 -0
- package/src/execution/WriteBackCard.tsx +285 -88
- package/src/execution/WriteBacksWidget.tsx +5 -5
- package/src/execution/__tests__/ToolCallItem.test.tsx +51 -0
- package/src/execution/__tests__/ToolRunGroup.test.tsx +22 -0
- package/src/execution/__tests__/WriteBackCard.test.tsx +64 -10
- package/src/execution/__tests__/write-back-utils.test.ts +135 -0
- package/src/execution/index.ts +7 -0
- package/src/execution/write-back-utils.ts +107 -0
- package/src/index.ts +34 -0
- package/src/internal/dev/__tests__/use-key-stability.test.ts +4 -0
- package/src/internal/dev/__tests__/use-render-tracer.test.ts +4 -0
- package/src/internal/dev/dom-counter.ts +2 -3
- package/src/internal/dev/enabled.ts +39 -0
- package/src/internal/dev/profiler-wrapper.tsx +5 -6
- package/src/internal/dev/use-key-stability.ts +2 -3
- package/src/internal/dev/use-render-tracer.ts +4 -5
- package/src/internal/dev/use-stream-rate.ts +4 -4
- package/src/library/ResourceVisibilityControl.tsx +23 -7
- package/src/library/__tests__/visibilityLevels.test.ts +33 -0
- package/src/library/useUpdateVisibility.ts +9 -3
- package/src/library/visibilityLevels.ts +36 -0
- package/src/session/NewSessionViewer.tsx +67 -31
- package/src/session/SessionViewer.tsx +67 -36
- package/src/session/__tests__/audienceWiring.test.tsx +99 -0
- package/src/session/__tests__/useNewSessionFlow.test.tsx +75 -1
- package/src/session/__tests__/useSessionPageFlow.guest.test.tsx +112 -0
- package/src/session/audience.ts +12 -4
- package/src/session/facets/ChangesTab.tsx +6 -4
- package/src/session/useNewSessionFlow.ts +26 -1
- package/src/session/useSessionPageFlow.ts +24 -2
- package/src/sharing/ShareAgentDialog.tsx +1255 -0
- package/src/sharing/SharedAgentChat.tsx +283 -0
- package/src/sharing/__tests__/ShareAgentDialog.test.tsx +745 -0
- package/src/sharing/__tests__/SharedAgentChat.test.tsx +222 -0
- package/src/sharing/__tests__/useRotateShareLink.test.tsx +96 -0
- package/src/sharing/__tests__/useShareAgent.test.tsx +127 -0
- package/src/sharing/__tests__/useShareToolReadiness.test.tsx +182 -0
- package/src/sharing/__tests__/useSharedAgentProfile.test.tsx +201 -0
- package/src/sharing/__tests__/useUpdateAgentSharing.test.tsx +200 -0
- package/src/sharing/index.ts +30 -0
- package/src/sharing/useRotateShareLink.ts +76 -0
- package/src/sharing/useShareAgent.tsx +106 -0
- package/src/sharing/useShareToolReadiness.ts +129 -0
- package/src/sharing/useSharedAgentProfile.ts +131 -0
- package/src/sharing/useUpdateAgentSharing.ts +151 -0
- package/src/switch/Switch.tsx +92 -0
- package/src/switch/__tests__/Switch.test.tsx +88 -0
- package/src/switch/index.ts +2 -0
- package/styles.css +1 -1
- package/switch/Switch.d.ts +47 -0
- package/switch/Switch.d.ts.map +1 -0
- package/switch/Switch.js +36 -0
- package/switch/Switch.js.map +1 -0
- package/switch/index.d.ts +3 -0
- package/switch/index.d.ts.map +1 -0
- package/switch/index.js +2 -0
- package/switch/index.js.map +1 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import type { Agent } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/api_pb";
|
|
2
|
+
import { AgentSharingAudience } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/spec_pb";
|
|
3
|
+
/**
|
|
4
|
+
* Who can chat with a shared agent over its hosted link.
|
|
5
|
+
*
|
|
6
|
+
* - `"public"` — anyone with the link; visitors are anonymous guests.
|
|
7
|
+
* - `"org"` — signed-in members of the owning organization only.
|
|
8
|
+
* Membership is checked on every conversation turn, so access ends the
|
|
9
|
+
* moment a member leaves the org.
|
|
10
|
+
*/
|
|
11
|
+
export type SharingAudience = "public" | "org";
|
|
12
|
+
/**
|
|
13
|
+
* A complete sharing configuration to persist.
|
|
14
|
+
*
|
|
15
|
+
* Every field is required by design: the `updateSharing` RPC **replaces**
|
|
16
|
+
* the agent's whole `spec.sharing` block, so a caller must always supply
|
|
17
|
+
* the full configuration. A partial type here would let a toggle change
|
|
18
|
+
* silently wipe `allowedOrigins`, `messages`, or the `audience` — the
|
|
19
|
+
* required shape makes that mistake unrepresentable.
|
|
20
|
+
*/
|
|
21
|
+
export interface AgentSharingDraft {
|
|
22
|
+
/** Whether hosted-chat access for the configured audience is enabled. */
|
|
23
|
+
readonly enabled: boolean;
|
|
24
|
+
/** Who can chat: anyone with the link, or org members only. */
|
|
25
|
+
readonly audience: SharingAudience;
|
|
26
|
+
/**
|
|
27
|
+
* Exact web origins allowed to embed the shared agent
|
|
28
|
+
* (e.g. `https://example.com`). Stored now; enforced by the embed
|
|
29
|
+
* widget's Origin check. Embedding is public-audience only.
|
|
30
|
+
*/
|
|
31
|
+
readonly allowedOrigins: readonly string[];
|
|
32
|
+
/** Owner-customized visitor refusal copy. Empty strings mean platform defaults. */
|
|
33
|
+
readonly messages: {
|
|
34
|
+
/** Shown when a visitor exceeds the message rate limit. */
|
|
35
|
+
readonly rateLimited: string;
|
|
36
|
+
/** Shown when the org's credits are exhausted (sharing fails closed). */
|
|
37
|
+
readonly unavailable: string;
|
|
38
|
+
/** Shown when a conversation hits its turn limit or inactivity timeout. */
|
|
39
|
+
readonly conversationEnded: string;
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Maps a proto {@link AgentSharingAudience} to the SDK's string union.
|
|
44
|
+
* Unspecified means public by contract (pre-audience shares keep their
|
|
45
|
+
* anyone-with-link behavior).
|
|
46
|
+
*/
|
|
47
|
+
export declare function sharingAudienceFromProto(audience: AgentSharingAudience | undefined): SharingAudience;
|
|
48
|
+
/** Return value of {@link useUpdateAgentSharing}. */
|
|
49
|
+
export interface UseUpdateAgentSharingReturn {
|
|
50
|
+
/**
|
|
51
|
+
* Persist the complete sharing configuration via the `updateSharing`
|
|
52
|
+
* RPC. Resolves with the updated agent.
|
|
53
|
+
*/
|
|
54
|
+
readonly updateSharing: (draft: AgentSharingDraft) => Promise<Agent | undefined>;
|
|
55
|
+
/** `true` while the RPC is in flight. */
|
|
56
|
+
readonly isPending: boolean;
|
|
57
|
+
/** The last error from the RPC, or `null`. */
|
|
58
|
+
readonly error: Error | null;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Behavior hook that updates an agent's sharing configuration.
|
|
62
|
+
*
|
|
63
|
+
* Wraps the targeted `stigmer.agent.updateSharing()` RPC (authorized by
|
|
64
|
+
* `can_edit`) with loading and error state management. The hook is
|
|
65
|
+
* stateless with respect to the agent — the caller refreshes the resource
|
|
66
|
+
* after a successful update (e.g. via `refetch` from `useAgent`), matching
|
|
67
|
+
* the {@link useUpdateVisibility} convention.
|
|
68
|
+
*
|
|
69
|
+
* Pass `null` for `agentId` to produce a stable no-op (useful while the
|
|
70
|
+
* agent is still loading).
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* ```tsx
|
|
74
|
+
* const { updateSharing, isPending } = useUpdateAgentSharing(agent.metadata.id);
|
|
75
|
+
*
|
|
76
|
+
* await updateSharing({
|
|
77
|
+
* enabled: true,
|
|
78
|
+
* audience: "public",
|
|
79
|
+
* allowedOrigins: ["https://example.com"],
|
|
80
|
+
* messages: { rateLimited: "", unavailable: "", conversationEnded: "" },
|
|
81
|
+
* });
|
|
82
|
+
* refetch();
|
|
83
|
+
* ```
|
|
84
|
+
*/
|
|
85
|
+
export declare function useUpdateAgentSharing(agentId: string | null): UseUpdateAgentSharingReturn;
|
|
86
|
+
//# sourceMappingURL=useUpdateAgentSharing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useUpdateAgentSharing.d.ts","sourceRoot":"","sources":["../../src/sharing/useUpdateAgentSharing.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,oDAAoD,CAAC;AAEhF,OAAO,EACL,oBAAoB,EAGrB,MAAM,qDAAqD,CAAC;AAI7D;;;;;;;GAOG;AACH,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,KAAK,CAAC;AAE/C;;;;;;;;GAQG;AACH,MAAM,WAAW,iBAAiB;IAChC,yEAAyE;IACzE,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,+DAA+D;IAC/D,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC;IACnC;;;;OAIG;IACH,QAAQ,CAAC,cAAc,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3C,mFAAmF;IACnF,QAAQ,CAAC,QAAQ,EAAE;QACjB,2DAA2D;QAC3D,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;QAC7B,yEAAyE;QACzE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;QAC7B,2EAA2E;QAC3E,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;KACpC,CAAC;CACH;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,oBAAoB,GAAG,SAAS,GACzC,eAAe,CAEjB;AAQD,qDAAqD;AACrD,MAAM,WAAW,2BAA2B;IAC1C;;;OAGG;IACH,QAAQ,CAAC,aAAa,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,OAAO,CAAC,KAAK,GAAG,SAAS,CAAC,CAAC;IACjF,yCAAyC;IACzC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,8CAA8C;IAC9C,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;CAC9B;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,MAAM,GAAG,IAAI,GACrB,2BAA2B,CAsC7B"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useCallback, useState } from "react";
|
|
3
|
+
import { create } from "@bufbuild/protobuf";
|
|
4
|
+
import { UpdateAgentSharingInputSchema } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/io_pb";
|
|
5
|
+
import { AgentSharingAudience, AgentSharingSchema, AgentSharingMessagesSchema, } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/spec_pb";
|
|
6
|
+
import { useStigmer } from "../hooks.js";
|
|
7
|
+
import { toError } from "../internal/toError.js";
|
|
8
|
+
/**
|
|
9
|
+
* Maps a proto {@link AgentSharingAudience} to the SDK's string union.
|
|
10
|
+
* Unspecified means public by contract (pre-audience shares keep their
|
|
11
|
+
* anyone-with-link behavior).
|
|
12
|
+
*/
|
|
13
|
+
export function sharingAudienceFromProto(audience) {
|
|
14
|
+
return audience === AgentSharingAudience.org ? "org" : "public";
|
|
15
|
+
}
|
|
16
|
+
function sharingAudienceToProto(audience) {
|
|
17
|
+
return audience === "org"
|
|
18
|
+
? AgentSharingAudience.org
|
|
19
|
+
: AgentSharingAudience.public;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Behavior hook that updates an agent's sharing configuration.
|
|
23
|
+
*
|
|
24
|
+
* Wraps the targeted `stigmer.agent.updateSharing()` RPC (authorized by
|
|
25
|
+
* `can_edit`) with loading and error state management. The hook is
|
|
26
|
+
* stateless with respect to the agent — the caller refreshes the resource
|
|
27
|
+
* after a successful update (e.g. via `refetch` from `useAgent`), matching
|
|
28
|
+
* the {@link useUpdateVisibility} convention.
|
|
29
|
+
*
|
|
30
|
+
* Pass `null` for `agentId` to produce a stable no-op (useful while the
|
|
31
|
+
* agent is still loading).
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```tsx
|
|
35
|
+
* const { updateSharing, isPending } = useUpdateAgentSharing(agent.metadata.id);
|
|
36
|
+
*
|
|
37
|
+
* await updateSharing({
|
|
38
|
+
* enabled: true,
|
|
39
|
+
* audience: "public",
|
|
40
|
+
* allowedOrigins: ["https://example.com"],
|
|
41
|
+
* messages: { rateLimited: "", unavailable: "", conversationEnded: "" },
|
|
42
|
+
* });
|
|
43
|
+
* refetch();
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export function useUpdateAgentSharing(agentId) {
|
|
47
|
+
const stigmer = useStigmer();
|
|
48
|
+
const [isPending, setIsPending] = useState(false);
|
|
49
|
+
const [error, setError] = useState(null);
|
|
50
|
+
const updateSharing = useCallback(async (draft) => {
|
|
51
|
+
if (!agentId)
|
|
52
|
+
return undefined;
|
|
53
|
+
setIsPending(true);
|
|
54
|
+
setError(null);
|
|
55
|
+
try {
|
|
56
|
+
const input = create(UpdateAgentSharingInputSchema, {
|
|
57
|
+
resourceId: agentId,
|
|
58
|
+
sharing: create(AgentSharingSchema, {
|
|
59
|
+
enabled: draft.enabled,
|
|
60
|
+
audience: sharingAudienceToProto(draft.audience),
|
|
61
|
+
allowedOrigins: [...draft.allowedOrigins],
|
|
62
|
+
messages: create(AgentSharingMessagesSchema, {
|
|
63
|
+
rateLimited: draft.messages.rateLimited,
|
|
64
|
+
unavailable: draft.messages.unavailable,
|
|
65
|
+
conversationEnded: draft.messages.conversationEnded,
|
|
66
|
+
}),
|
|
67
|
+
}),
|
|
68
|
+
});
|
|
69
|
+
return await stigmer.agent.updateSharing(input);
|
|
70
|
+
}
|
|
71
|
+
catch (err) {
|
|
72
|
+
setError(toError(err));
|
|
73
|
+
throw err;
|
|
74
|
+
}
|
|
75
|
+
finally {
|
|
76
|
+
setIsPending(false);
|
|
77
|
+
}
|
|
78
|
+
}, [agentId, stigmer]);
|
|
79
|
+
return { updateSharing, isPending, error };
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=useUpdateAgentSharing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useUpdateAgentSharing.js","sourceRoot":"","sources":["../../src/sharing/useUpdateAgentSharing.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAE5C,OAAO,EAAE,6BAA6B,EAAE,MAAM,mDAAmD,CAAC;AAClG,OAAO,EACL,oBAAoB,EACpB,kBAAkB,EAClB,0BAA0B,GAC3B,MAAM,qDAAqD,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AA2CjD;;;;GAIG;AACH,MAAM,UAAU,wBAAwB,CACtC,QAA0C;IAE1C,OAAO,QAAQ,KAAK,oBAAoB,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC;AAClE,CAAC;AAED,SAAS,sBAAsB,CAAC,QAAyB;IACvD,OAAO,QAAQ,KAAK,KAAK;QACvB,CAAC,CAAC,oBAAoB,CAAC,GAAG;QAC1B,CAAC,CAAC,oBAAoB,CAAC,MAAM,CAAC;AAClC,CAAC;AAeD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,UAAU,qBAAqB,CACnC,OAAsB;IAEtB,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;IAC7B,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAClD,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAe,IAAI,CAAC,CAAC;IAEvD,MAAM,aAAa,GAAG,WAAW,CAC/B,KAAK,EAAE,KAAwB,EAA8B,EAAE;QAC7D,IAAI,CAAC,OAAO;YAAE,OAAO,SAAS,CAAC;QAE/B,YAAY,CAAC,IAAI,CAAC,CAAC;QACnB,QAAQ,CAAC,IAAI,CAAC,CAAC;QAEf,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,MAAM,CAAC,6BAA6B,EAAE;gBAClD,UAAU,EAAE,OAAO;gBACnB,OAAO,EAAE,MAAM,CAAC,kBAAkB,EAAE;oBAClC,OAAO,EAAE,KAAK,CAAC,OAAO;oBACtB,QAAQ,EAAE,sBAAsB,CAAC,KAAK,CAAC,QAAQ,CAAC;oBAChD,cAAc,EAAE,CAAC,GAAG,KAAK,CAAC,cAAc,CAAC;oBACzC,QAAQ,EAAE,MAAM,CAAC,0BAA0B,EAAE;wBAC3C,WAAW,EAAE,KAAK,CAAC,QAAQ,CAAC,WAAW;wBACvC,WAAW,EAAE,KAAK,CAAC,QAAQ,CAAC,WAAW;wBACvC,iBAAiB,EAAE,KAAK,CAAC,QAAQ,CAAC,iBAAiB;qBACpD,CAAC;iBACH,CAAC;aACH,CAAC,CAAC;YACH,OAAO,MAAM,OAAO,CAAC,KAAK,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;QAClD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;YACvB,MAAM,GAAG,CAAC;QACZ,CAAC;gBAAS,CAAC;YACT,YAAY,CAAC,KAAK,CAAC,CAAC;QACtB,CAAC;IACH,CAAC,EACD,CAAC,OAAO,EAAE,OAAO,CAAC,CACnB,CAAC;IAEF,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;AAC7C,CAAC"}
|
|
@@ -17,6 +17,7 @@ import { agentToInput } from "./internal/agentToInput.js";
|
|
|
17
17
|
import { ErrorMessage } from "../error/ErrorMessage.js";
|
|
18
18
|
import { VisibilityBadge } from "../library/VisibilitySelector.js";
|
|
19
19
|
import { useManageAccess } from "../access/useManageAccess.js";
|
|
20
|
+
import { useShareAgent } from "../sharing/useShareAgent.js";
|
|
20
21
|
import { ResourceDetailShell } from "../resource-detail/ResourceDetailShell.js";
|
|
21
22
|
import { Section } from "../resource-detail/Section.js";
|
|
22
23
|
import { useDetailTabs } from "../resource-detail/useDetailTabs.js";
|
|
@@ -127,6 +128,14 @@ export interface AgentDetailViewProps {
|
|
|
127
128
|
* Opens the create instance dialog.
|
|
128
129
|
*/
|
|
129
130
|
readonly onCreateInstanceClick?: () => void;
|
|
131
|
+
/**
|
|
132
|
+
* Builds the absolute public chat URL shown in the Share dialog.
|
|
133
|
+
* The host application owns URL construction — its configured public
|
|
134
|
+
* origin may differ from the rendering origin (e.g. the desktop app).
|
|
135
|
+
* When omitted, the dialog falls back to the relative
|
|
136
|
+
* `/chat/<org>/<slug>` path.
|
|
137
|
+
*/
|
|
138
|
+
readonly buildShareUrl?: (org: string, slug: string) => string;
|
|
130
139
|
/**
|
|
131
140
|
* Called when the user clicks an instance row in the Instances tab.
|
|
132
141
|
* Typically opens an instance detail panel.
|
|
@@ -204,6 +213,7 @@ export function AgentDetailView({
|
|
|
204
213
|
defaultTab,
|
|
205
214
|
editable = false,
|
|
206
215
|
onResourceUpdated,
|
|
216
|
+
buildShareUrl,
|
|
207
217
|
onCreateInstanceClick,
|
|
208
218
|
onInstanceClick,
|
|
209
219
|
onInstanceStartSessionClick,
|
|
@@ -306,6 +316,15 @@ export function AgentDetailView({
|
|
|
306
316
|
: undefined,
|
|
307
317
|
});
|
|
308
318
|
|
|
319
|
+
// Share — the sibling consent to Manage access: visibility governs who
|
|
320
|
+
// can read the blueprint; sharing governs who can chat with the running
|
|
321
|
+
// agent (billed to the owning org). Same null-until-ready contract.
|
|
322
|
+
const share = useShareAgent({
|
|
323
|
+
agent,
|
|
324
|
+
buildShareUrl,
|
|
325
|
+
onSharingChanged: refetch,
|
|
326
|
+
});
|
|
327
|
+
|
|
309
328
|
if (isLoading) return <LoadingSkeleton className={className} />;
|
|
310
329
|
if (error)
|
|
311
330
|
return <ErrorMessage error={error} retry={refetch} className={className} />;
|
|
@@ -344,9 +363,14 @@ export function AgentDetailView({
|
|
|
344
363
|
<VisibilityBadge visibility={meta.visibility} />
|
|
345
364
|
) : undefined;
|
|
346
365
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
:
|
|
366
|
+
// Share precedes Manage access within the "sharing" group.
|
|
367
|
+
const injectedActions = [share.action, access.action].filter(
|
|
368
|
+
(a): a is NonNullable<typeof a> => a != null,
|
|
369
|
+
);
|
|
370
|
+
const mergedActions =
|
|
371
|
+
injectedActions.length > 0
|
|
372
|
+
? [...(actions ?? []), ...injectedActions]
|
|
373
|
+
: actions;
|
|
350
374
|
|
|
351
375
|
let tabContent: React.ReactNode;
|
|
352
376
|
if (activeAdditionalTab) {
|
|
@@ -402,6 +426,7 @@ export function AgentDetailView({
|
|
|
402
426
|
{tabContent}
|
|
403
427
|
</ResourceDetailShell>
|
|
404
428
|
{access.dialog}
|
|
429
|
+
{share.dialog}
|
|
405
430
|
</>
|
|
406
431
|
);
|
|
407
432
|
}
|
|
@@ -4,8 +4,11 @@ import { useCallback, useMemo, useState } from "react";
|
|
|
4
4
|
import { cn } from "@stigmer/theme";
|
|
5
5
|
import { getUserMessage } from "@stigmer/sdk";
|
|
6
6
|
import type { Environment } from "@stigmer/protos/ai/stigmer/agentic/environment/v1/api_pb";
|
|
7
|
+
import { ApiResourceVisibility } from "@stigmer/protos/ai/stigmer/commons/apiresource/enum_pb";
|
|
8
|
+
import { ResourceVisibilityControl } from "../library/ResourceVisibilityControl.js";
|
|
7
9
|
import { useEnvironmentList } from "./useEnvironmentList.js";
|
|
8
10
|
import { EnvironmentVariableEditor } from "./EnvironmentVariableEditor.js";
|
|
11
|
+
import { isShareRestrictedEnvironment } from "./shareRestriction.js";
|
|
9
12
|
|
|
10
13
|
// ---------------------------------------------------------------------------
|
|
11
14
|
// Public API
|
|
@@ -175,6 +178,7 @@ export function EnvironmentListPanel({
|
|
|
175
178
|
isExpanded={isExpanded}
|
|
176
179
|
onToggle={() => handleToggle(env)}
|
|
177
180
|
readOnly={readOnly}
|
|
181
|
+
onVisibilityChanged={refetch}
|
|
178
182
|
/>
|
|
179
183
|
);
|
|
180
184
|
})}
|
|
@@ -191,11 +195,13 @@ function EnvironmentCard({
|
|
|
191
195
|
isExpanded,
|
|
192
196
|
onToggle,
|
|
193
197
|
readOnly,
|
|
198
|
+
onVisibilityChanged,
|
|
194
199
|
}: {
|
|
195
200
|
environment: Environment;
|
|
196
201
|
isExpanded: boolean;
|
|
197
202
|
onToggle: () => void;
|
|
198
203
|
readOnly: boolean;
|
|
204
|
+
onVisibilityChanged: () => void;
|
|
199
205
|
}) {
|
|
200
206
|
const name =
|
|
201
207
|
environment.metadata?.name || environment.metadata?.slug || "Unnamed";
|
|
@@ -203,6 +209,12 @@ function EnvironmentCard({
|
|
|
203
209
|
const variableCount = Object.keys(environment.spec?.data ?? {}).length;
|
|
204
210
|
const environmentId = environment.metadata?.id ?? "";
|
|
205
211
|
|
|
212
|
+
// Personal and OAuth-managed environments are never org-shareable
|
|
213
|
+
// (the backend rejects the transition) — offering the control would
|
|
214
|
+
// be an error trap, so it is structurally absent for them.
|
|
215
|
+
const showVisibilityControl =
|
|
216
|
+
!readOnly && environmentId !== "" && !isShareRestrictedEnvironment(environment);
|
|
217
|
+
|
|
206
218
|
return (
|
|
207
219
|
<div
|
|
208
220
|
role="listitem"
|
|
@@ -213,30 +225,47 @@ function EnvironmentCard({
|
|
|
213
225
|
: "border-border-muted hover:border-border",
|
|
214
226
|
)}
|
|
215
227
|
>
|
|
216
|
-
{/* Header — always visible
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
228
|
+
{/* Header — always visible. The expand toggle and the visibility
|
|
229
|
+
control are sibling interactive elements (nesting the selector
|
|
230
|
+
inside the toggle button would be invalid markup). */}
|
|
231
|
+
<div className="flex w-full items-center gap-3 px-3 py-2.5">
|
|
232
|
+
<button
|
|
233
|
+
type="button"
|
|
234
|
+
onClick={onToggle}
|
|
235
|
+
aria-expanded={isExpanded}
|
|
236
|
+
className="flex min-w-0 flex-1 items-center gap-3 text-left"
|
|
237
|
+
>
|
|
238
|
+
<ChevronIcon expanded={isExpanded} />
|
|
224
239
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
</span>
|
|
229
|
-
{description && (
|
|
230
|
-
<span className="block truncate text-xs text-muted-foreground">
|
|
231
|
-
{description}
|
|
240
|
+
<div className="min-w-0 flex-1">
|
|
241
|
+
<span className="block truncate text-sm font-medium text-foreground">
|
|
242
|
+
{name}
|
|
232
243
|
</span>
|
|
233
|
-
|
|
234
|
-
|
|
244
|
+
{description && (
|
|
245
|
+
<span className="block truncate text-xs text-muted-foreground">
|
|
246
|
+
{description}
|
|
247
|
+
</span>
|
|
248
|
+
)}
|
|
249
|
+
</div>
|
|
250
|
+
</button>
|
|
251
|
+
|
|
252
|
+
{showVisibilityControl && (
|
|
253
|
+
<ResourceVisibilityControl
|
|
254
|
+
kind="environment"
|
|
255
|
+
resourceId={environmentId}
|
|
256
|
+
visibility={
|
|
257
|
+
environment.metadata?.visibility ??
|
|
258
|
+
ApiResourceVisibility.visibility_private
|
|
259
|
+
}
|
|
260
|
+
onChanged={onVisibilityChanged}
|
|
261
|
+
className="shrink-0"
|
|
262
|
+
/>
|
|
263
|
+
)}
|
|
235
264
|
|
|
236
265
|
<span className="shrink-0 text-xs text-muted-foreground">
|
|
237
266
|
{variableCount} {variableCount === 1 ? "variable" : "variables"}
|
|
238
267
|
</span>
|
|
239
|
-
</
|
|
268
|
+
</div>
|
|
240
269
|
|
|
241
270
|
{/* Expanded content — variable editor */}
|
|
242
271
|
{isExpanded && environmentId && (
|
|
@@ -12,6 +12,7 @@ import { getUserMessage, type EnvVarInput } from "@stigmer/sdk";
|
|
|
12
12
|
import type { Environment } from "@stigmer/protos/ai/stigmer/agentic/environment/v1/api_pb";
|
|
13
13
|
import { useStigmer } from "../hooks.js";
|
|
14
14
|
import { toError } from "../internal/toError.js";
|
|
15
|
+
import { PermissionGate } from "../iam-policy/PermissionGate.js";
|
|
15
16
|
import { useUpdateEnvironmentVariables } from "./useUpdateEnvironmentVariables.js";
|
|
16
17
|
import { useRemoveEnvironmentVariables } from "./useRemoveEnvironmentVariables.js";
|
|
17
18
|
import { useRevealSecretValue } from "./useRevealSecretValue.js";
|
|
@@ -438,24 +439,33 @@ function VariableRow({
|
|
|
438
439
|
!readOnly && (
|
|
439
440
|
<div className="flex shrink-0 items-center gap-0.5 opacity-0 transition-opacity group-hover:opacity-100 group-focus-within:opacity-100">
|
|
440
441
|
{variable.isSecret && (
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
}
|
|
449
|
-
variant="muted"
|
|
442
|
+
/* Secret reveal is creator-only (can_read_secrets) at every
|
|
443
|
+
visibility level — org sharing never widens it. Hide the
|
|
444
|
+
affordance for everyone else instead of offering a button
|
|
445
|
+
that is guaranteed to fail (error prevention). */
|
|
446
|
+
<PermissionGate
|
|
447
|
+
resource={{ kind: "environment", id: environmentId }}
|
|
448
|
+
relation="can_read_secrets"
|
|
450
449
|
>
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
450
|
+
<ActionButton
|
|
451
|
+
onClick={toggleReveal}
|
|
452
|
+
disabled={isRevealing}
|
|
453
|
+
label={
|
|
454
|
+
revealedValue !== null
|
|
455
|
+
? `Hide ${variable.key}`
|
|
456
|
+
: `Reveal ${variable.key}`
|
|
457
|
+
}
|
|
458
|
+
variant="muted"
|
|
459
|
+
>
|
|
460
|
+
{isRevealing ? (
|
|
461
|
+
<SpinnerIcon />
|
|
462
|
+
) : revealedValue !== null ? (
|
|
463
|
+
<EyeOffIcon />
|
|
464
|
+
) : (
|
|
465
|
+
<EyeIcon />
|
|
466
|
+
)}
|
|
467
|
+
</ActionButton>
|
|
468
|
+
</PermissionGate>
|
|
459
469
|
)}
|
|
460
470
|
<ActionButton
|
|
461
471
|
onClick={startEdit}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { create } from "@bufbuild/protobuf";
|
|
3
|
+
import { EnvironmentSchema } from "@stigmer/protos/ai/stigmer/agentic/environment/v1/api_pb";
|
|
4
|
+
import { isShareRestrictedEnvironment } from "../shareRestriction";
|
|
5
|
+
|
|
6
|
+
function env(labels: Record<string, string>) {
|
|
7
|
+
return create(EnvironmentSchema, {
|
|
8
|
+
metadata: { id: "env_1", org: "acme", labels },
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
describe("isShareRestrictedEnvironment", () => {
|
|
13
|
+
it("restricts personal environments", () => {
|
|
14
|
+
expect(
|
|
15
|
+
isShareRestrictedEnvironment(env({ "stigmer.ai/personal": "true" })),
|
|
16
|
+
).toBe(true);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it("restricts OAuth-managed environments", () => {
|
|
20
|
+
expect(
|
|
21
|
+
isShareRestrictedEnvironment(env({ "stigmer.ai/managed": "true" })),
|
|
22
|
+
).toBe(true);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it("does not restrict ordinary environments", () => {
|
|
26
|
+
expect(isShareRestrictedEnvironment(env({}))).toBe(false);
|
|
27
|
+
expect(isShareRestrictedEnvironment(env({ team: "payments" }))).toBe(false);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("only the literal 'true' value restricts", () => {
|
|
31
|
+
expect(
|
|
32
|
+
isShareRestrictedEnvironment(env({ "stigmer.ai/personal": "false" })),
|
|
33
|
+
).toBe(false);
|
|
34
|
+
});
|
|
35
|
+
});
|
package/src/environment/index.ts
CHANGED
|
@@ -50,3 +50,8 @@ export {
|
|
|
50
50
|
} from "./systemEnvVars.js";
|
|
51
51
|
export { EnvironmentPicker } from "./EnvironmentPicker.js";
|
|
52
52
|
export type { EnvironmentPickerProps } from "./EnvironmentPicker.js";
|
|
53
|
+
export {
|
|
54
|
+
PERSONAL_ENV_LABEL,
|
|
55
|
+
MANAGED_ENV_LABEL,
|
|
56
|
+
isShareRestrictedEnvironment,
|
|
57
|
+
} from "./shareRestriction.js";
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Environment } from "@stigmer/protos/ai/stigmer/agentic/environment/v1/api_pb";
|
|
2
|
+
|
|
3
|
+
/** Label marking a user's personal credential-fallback environment. */
|
|
4
|
+
export const PERSONAL_ENV_LABEL = "stigmer.ai/personal";
|
|
5
|
+
|
|
6
|
+
/** Label marking a system-managed environment holding per-user OAuth tokens. */
|
|
7
|
+
export const MANAGED_ENV_LABEL = "stigmer.ai/managed";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Whether an environment is share-restricted — personal and OAuth-managed
|
|
11
|
+
* environments must never carry org visibility, so surfaces hide the
|
|
12
|
+
* sharing control for them entirely (error prevention: the backend
|
|
13
|
+
* rejects the transition with FAILED_PRECONDITION in both editions).
|
|
14
|
+
*/
|
|
15
|
+
export function isShareRestrictedEnvironment(
|
|
16
|
+
environment: Environment,
|
|
17
|
+
): boolean {
|
|
18
|
+
const labels = environment.metadata?.labels ?? {};
|
|
19
|
+
return (
|
|
20
|
+
labels[PERSONAL_ENV_LABEL] === "true" || labels[MANAGED_ENV_LABEL] === "true"
|
|
21
|
+
);
|
|
22
|
+
}
|
|
@@ -454,7 +454,7 @@ const REVIEW_BADGE: Record<FileReviewRowState, ApprovalBadgeInfo> = {
|
|
|
454
454
|
// Status mapping
|
|
455
455
|
// ---------------------------------------------------------------------------
|
|
456
456
|
|
|
457
|
-
type ItemStatus = "running" | "waiting" | "failed" | "completed" | "pending";
|
|
457
|
+
type ItemStatus = "running" | "waiting" | "failed" | "completed" | "pending" | "interrupted";
|
|
458
458
|
|
|
459
459
|
function mapToolCallStatus(toolCall: ToolCall): ItemStatus {
|
|
460
460
|
switch (toolCall.status) {
|
|
@@ -474,6 +474,12 @@ function mapToolCallStatus(toolCall: ToolCall): ItemStatus {
|
|
|
474
474
|
case ToolCallStatus.TOOL_CALL_COMPLETED:
|
|
475
475
|
case ToolCallStatus.TOOL_CALL_SKIPPED:
|
|
476
476
|
return "completed";
|
|
477
|
+
// Platform-settled when the execution terminalized mid-call (issue #207).
|
|
478
|
+
// A settled, neutral state: not a spinner (nothing is running), not a
|
|
479
|
+
// failure (the tool never errored), not a grey pending dot (it will never
|
|
480
|
+
// start).
|
|
481
|
+
case ToolCallStatus.TOOL_CALL_INTERRUPTED:
|
|
482
|
+
return "interrupted";
|
|
477
483
|
default:
|
|
478
484
|
return "pending";
|
|
479
485
|
}
|
|
@@ -485,6 +491,7 @@ const STATUS_COLOR: Record<ItemStatus, string> = {
|
|
|
485
491
|
failed: "text-destructive",
|
|
486
492
|
completed: "text-success",
|
|
487
493
|
pending: "text-muted-foreground",
|
|
494
|
+
interrupted: "text-muted-foreground",
|
|
488
495
|
};
|
|
489
496
|
|
|
490
497
|
// ---------------------------------------------------------------------------
|
|
@@ -626,6 +633,7 @@ const STATUS_ICON: Record<ItemStatus, () => React.JSX.Element> = {
|
|
|
626
633
|
failed: XCircleIcon,
|
|
627
634
|
completed: CheckCircleIcon,
|
|
628
635
|
pending: DotIcon,
|
|
636
|
+
interrupted: SlashCircleIcon,
|
|
629
637
|
};
|
|
630
638
|
|
|
631
639
|
function SpinnerIcon() {
|
|
@@ -671,6 +679,16 @@ function DotIcon() {
|
|
|
671
679
|
);
|
|
672
680
|
}
|
|
673
681
|
|
|
682
|
+
/** Slashed circle for an interrupted call — settled, neutral, visibly "cut short". */
|
|
683
|
+
function SlashCircleIcon() {
|
|
684
|
+
return (
|
|
685
|
+
<svg width="10" height="10" viewBox="0 0 12 12" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round">
|
|
686
|
+
<circle cx="6" cy="6" r="4.5" />
|
|
687
|
+
<path d="M2.8 9.2L9.2 2.8" />
|
|
688
|
+
</svg>
|
|
689
|
+
);
|
|
690
|
+
}
|
|
691
|
+
|
|
674
692
|
function InspectIcon() {
|
|
675
693
|
return (
|
|
676
694
|
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
|
|
@@ -202,6 +202,10 @@ function deriveAggregateStatus(toolCalls: readonly ToolCall[]): AggregateStatus
|
|
|
202
202
|
break;
|
|
203
203
|
case ToolCallStatus.TOOL_CALL_COMPLETED:
|
|
204
204
|
case ToolCallStatus.TOOL_CALL_SKIPPED:
|
|
205
|
+
// INTERRUPTED is terminal (platform-settled when the execution
|
|
206
|
+
// terminalized mid-call, issue #207): the chip must settle, not pin to
|
|
207
|
+
// "pending" forever.
|
|
208
|
+
case ToolCallStatus.TOOL_CALL_INTERRUPTED:
|
|
205
209
|
break;
|
|
206
210
|
default:
|
|
207
211
|
allTerminal = false;
|