@agent-native/core 0.198.3 → 0.198.5
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/a2a/types.d.ts +5 -0
- package/dist/agent/production-agent.js +26 -1
- package/dist/catalog.json +1 -0
- package/dist/client/chat/agentkit-agent-native.js +15 -15
- package/dist/client/chat/runtime.js +5 -3
- package/dist/client/feature-flags/types.d.ts +2 -0
- package/dist/client/i18n.d.ts +2 -0
- package/dist/client/i18n.js +2 -0
- package/dist/client/integrations/index.d.ts +1 -0
- package/dist/client/integrations/index.js +1 -0
- package/dist/client/labs/index.d.ts +1 -1
- package/dist/client/labs/use-lab.d.ts +5 -0
- package/dist/client/labs/use-lab.js +7 -3
- package/dist/client/resources/mcp-connection-resume.d.ts +5 -3
- package/dist/client/resources/mcp-connection-resume.js +150 -13
- package/dist/client/sse-event-processor.d.ts +6 -0
- package/dist/client/uploads/index.d.ts +1 -0
- package/dist/client/uploads/index.js +1 -0
- package/dist/client/uploads/private-icon.d.ts +10 -0
- package/dist/client/uploads/private-icon.js +52 -0
- package/dist/collab/routes.d.ts +2 -2
- package/dist/feature-flags/actions/get-feature-flags.js +20 -0
- package/dist/feature-flags/actions/list-feature-flags.d.ts +2 -0
- package/dist/feature-flags/actions/list-feature-flags.js +5 -0
- package/dist/feature-flags/actions/set-feature-flag.js +5 -0
- package/dist/file-upload/actions/upload-image.d.ts +3 -3
- package/dist/framework-tools.js +2 -0
- package/dist/icon-assets/index.d.ts +3 -0
- package/dist/icon-assets/index.js +3 -0
- package/dist/icon-assets/multipart.d.ts +9 -0
- package/dist/icon-assets/multipart.js +60 -0
- package/dist/icon-assets/schema.d.ts +194 -0
- package/dist/icon-assets/schema.js +16 -0
- package/dist/icon-assets/store.d.ts +38 -0
- package/dist/icon-assets/store.js +187 -0
- package/dist/icon-assets/svg.d.ts +2 -0
- package/dist/icon-assets/svg.js +146 -0
- package/dist/icon-assets/workspace-transport.d.ts +20 -0
- package/dist/icon-assets/workspace-transport.js +122 -0
- package/dist/identity/rekey.js +1 -0
- package/dist/jobs/actions/manage-recurring-job.d.ts +1 -1
- package/dist/labs/actions/get-lab-states.d.ts +2 -0
- package/dist/labs/actions/get-lab-states.js +14 -0
- package/dist/labs/actions/get-labs.js +2 -2
- package/dist/labs/actions/set-lab.js +4 -2
- package/dist/labs/index.d.ts +1 -1
- package/dist/labs/index.js +1 -1
- package/dist/labs/registry.d.ts +3 -0
- package/dist/labs/registry.js +14 -0
- package/dist/labs/server.d.ts +1 -1
- package/dist/labs/server.js +1 -1
- package/dist/labs/store.d.ts +13 -2
- package/dist/labs/store.js +124 -7
- package/dist/localization/default-messages.d.ts +2 -0
- package/dist/localization/default-messages.js +1 -1
- package/dist/localization/icon-picker-messages.d.ts +44 -0
- package/dist/localization/icon-picker-messages.js +22 -0
- package/dist/mcp-client/oauth-client.d.ts +1 -0
- package/dist/mcp-client/oauth-client.js +42 -4
- package/dist/mcp-client/oauth-routes.js +15 -2
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/observability/routes.d.ts +9 -9
- package/dist/org/actions/list-workspace-icons.d.ts +7 -0
- package/dist/org/actions/list-workspace-icons.js +41 -0
- package/dist/org/handlers.d.ts +1 -1
- package/dist/org/handlers.js +28 -1
- package/dist/org/index.d.ts +1 -1
- package/dist/org/migrations.js +21 -0
- package/dist/org/plugin.js +42 -0
- package/dist/org/private-icon-handlers.d.ts +6 -0
- package/dist/org/private-icon-handlers.js +212 -0
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +8 -8
- package/dist/provider-api/actions/provider-api.d.ts +5 -5
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/provider-api/index.d.ts +1 -1
- package/dist/provider-api/index.js +26 -6
- package/dist/secrets/routes.d.ts +4 -4
- package/dist/server/action-discovery.js +5 -0
- package/dist/server/agent-chat-plugin.js +14 -0
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/agent-engine-default-model-route.d.ts +1 -1
- package/dist/server/agent-engine-ollama-models-route.d.ts +1 -1
- package/dist/server/core-routes-plugin.d.ts +1 -1
- package/dist/server/core-routes-plugin.js +18 -3
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.js +1 -1
- package/dist/server/workspace-provider-oauth.d.ts +1 -0
- package/dist/server/workspace-provider-oauth.js +4 -2
- package/dist/templates/chat/app/components/chat/ChatRouteContent.tsx +9 -16
- package/dist/triggers/actions/manage-automation.d.ts +5 -5
- package/dist/vite/action-types-plugin.js +4 -0
- package/package.json +7 -9
- package/src/templates/chat/app/components/chat/ChatRouteContent.tsx +9 -16
package/dist/a2a/types.d.ts
CHANGED
|
@@ -49,6 +49,11 @@ export interface A2AConnectionRequestMetadata {
|
|
|
49
49
|
reason: "connect" | "grant" | "reauthorize" | "admin_required";
|
|
50
50
|
appId?: string;
|
|
51
51
|
detail?: string;
|
|
52
|
+
source?: {
|
|
53
|
+
id: string;
|
|
54
|
+
kind: "workspace_connection";
|
|
55
|
+
label?: string;
|
|
56
|
+
};
|
|
52
57
|
}
|
|
53
58
|
export interface AgentSkill {
|
|
54
59
|
id: string;
|
|
@@ -1656,7 +1656,11 @@ export async function callConnectedAgentReference(input) {
|
|
|
1656
1656
|
...(connectionRequest.appId
|
|
1657
1657
|
? { appId: connectionRequest.appId }
|
|
1658
1658
|
: {}),
|
|
1659
|
-
source:
|
|
1659
|
+
source: connectionRequest.source ?? {
|
|
1660
|
+
id: input.agent,
|
|
1661
|
+
kind: "agent",
|
|
1662
|
+
label: input.agent,
|
|
1663
|
+
},
|
|
1660
1664
|
});
|
|
1661
1665
|
}
|
|
1662
1666
|
relay.finish("error");
|
|
@@ -1684,12 +1688,28 @@ function parseA2AConnectionRequest(error) {
|
|
|
1684
1688
|
}
|
|
1685
1689
|
const appId = typeof request.appId === "string" ? request.appId.trim() : "";
|
|
1686
1690
|
const detail = typeof request.detail === "string" ? request.detail.trim() : "";
|
|
1691
|
+
const sourceValue = request.source && typeof request.source === "object"
|
|
1692
|
+
? request.source
|
|
1693
|
+
: null;
|
|
1694
|
+
const sourceId = typeof sourceValue?.id === "string" ? sourceValue.id.trim() : "";
|
|
1695
|
+
const sourceLabel = typeof sourceValue?.label === "string" ? sourceValue.label.trim() : "";
|
|
1687
1696
|
return {
|
|
1688
1697
|
version: 1,
|
|
1689
1698
|
provider,
|
|
1690
1699
|
reason,
|
|
1691
1700
|
...(appId && appId.length <= 120 ? { appId } : {}),
|
|
1692
1701
|
...(detail && detail.length <= 1_000 ? { detail } : {}),
|
|
1702
|
+
...(sourceValue?.kind === "workspace_connection" &&
|
|
1703
|
+
sourceId === provider &&
|
|
1704
|
+
sourceId.length <= 120
|
|
1705
|
+
? {
|
|
1706
|
+
source: {
|
|
1707
|
+
id: sourceId,
|
|
1708
|
+
kind: "workspace_connection",
|
|
1709
|
+
...(sourceLabel ? { label: sourceLabel.slice(0, 120) } : {}),
|
|
1710
|
+
},
|
|
1711
|
+
}
|
|
1712
|
+
: {}),
|
|
1693
1713
|
};
|
|
1694
1714
|
}
|
|
1695
1715
|
const MAX_CONNECTED_AGENT_PROGRESS_DETAIL_CHARS = 200;
|
|
@@ -2648,6 +2668,11 @@ export function permanentPreconditionReason(toolName, message) {
|
|
|
2648
2668
|
.trim()
|
|
2649
2669
|
// The headline appends its own sentence punctuation.
|
|
2650
2670
|
.replace(/[.。]+$/, "");
|
|
2671
|
+
const nestedPrecondition = reason
|
|
2672
|
+
.match(/\bI stopped because [\w-]+ can't run yet:\s*(.+?)\. That needs to be fixed outside this chat\b/i)?.[1]
|
|
2673
|
+
?.trim();
|
|
2674
|
+
if (nestedPrecondition)
|
|
2675
|
+
return nestedPrecondition;
|
|
2651
2676
|
if (!reason)
|
|
2652
2677
|
return null;
|
|
2653
2678
|
if (/\bI stopped because\b/i.test(reason) ||
|
package/dist/catalog.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
|
+
import { AgentKitRunSlotBusyError } from "@agent-native/agentkit/client";
|
|
1
2
|
import { isAgentKitProtocolVersion, parseAgentThreadSnapshot, } from "@agent-native/agentkit/protocol";
|
|
2
3
|
import { agentNativePath } from "../api-path.js";
|
|
3
4
|
import { dispatchAgentChatRunning } from "../use-agent-chat-running-threads.js";
|
|
4
5
|
import { appendChatThreadScopeParams, } from "../use-chat-threads.js";
|
|
5
6
|
import { AGENT_NATIVE_PROTOCOL_METADATA_KEY, createAgentKitProtocolAdapter, } from "./agentkit-protocol.js";
|
|
6
7
|
import { createAgentNativeChatRuntime, } from "./runtime.js";
|
|
7
|
-
const RUN_SLOT_TIMEOUT_MS = 5_000;
|
|
8
8
|
const RUN_SLOT_POLL_INTERVAL_MS = 150;
|
|
9
9
|
const RUN_SLOT_STABLE_POLLS = 2;
|
|
10
|
+
const RUN_SLOT_MAX_POLLS = RUN_SLOT_STABLE_POLLS * 2;
|
|
10
11
|
function asRecord(value) {
|
|
11
12
|
return value && typeof value === "object" && !Array.isArray(value)
|
|
12
13
|
? value
|
|
@@ -954,9 +955,8 @@ export function createAgentNativeAgentKitTransport(options = {}) {
|
|
|
954
955
|
};
|
|
955
956
|
}
|
|
956
957
|
async function waitForRunSlot(threadId) {
|
|
957
|
-
const deadline = Date.now() + RUN_SLOT_TIMEOUT_MS;
|
|
958
958
|
let consecutiveClearPolls = 0;
|
|
959
|
-
|
|
959
|
+
for (let poll = 0; poll < RUN_SLOT_MAX_POLLS; poll += 1) {
|
|
960
960
|
const response = await fetcher(`${apiUrl}/runs/active?threadId=${encodeURIComponent(threadId)}`, { headers: await headers({ sessionId: threadId }) });
|
|
961
961
|
if (!response.ok)
|
|
962
962
|
throw await responseError(response);
|
|
@@ -964,22 +964,22 @@ export function createAgentNativeAgentKitTransport(options = {}) {
|
|
|
964
964
|
if (!status) {
|
|
965
965
|
throw new TypeError("Agent chat active-run response must be an object.");
|
|
966
966
|
}
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
status.status === "errored" ||
|
|
976
|
-
status.status === "aborted";
|
|
967
|
+
const clear = status.awaitingRedispatch !== true &&
|
|
968
|
+
(status.active !== true ||
|
|
969
|
+
status.status === "completed" ||
|
|
970
|
+
status.status === "complete" ||
|
|
971
|
+
status.status === "failed" ||
|
|
972
|
+
status.status === "cancelled" ||
|
|
973
|
+
status.status === "errored" ||
|
|
974
|
+
status.status === "aborted");
|
|
977
975
|
consecutiveClearPolls = clear ? consecutiveClearPolls + 1 : 0;
|
|
978
976
|
if (consecutiveClearPolls >= RUN_SLOT_STABLE_POLLS)
|
|
979
977
|
return;
|
|
980
|
-
|
|
978
|
+
if (poll + 1 < RUN_SLOT_MAX_POLLS) {
|
|
979
|
+
await new Promise((resolve) => setTimeout(resolve, RUN_SLOT_POLL_INTERVAL_MS));
|
|
980
|
+
}
|
|
981
981
|
}
|
|
982
|
-
throw new
|
|
982
|
+
throw new AgentKitRunSlotBusyError();
|
|
983
983
|
}
|
|
984
984
|
async function readQueue(threadId) {
|
|
985
985
|
const thread = await snapshot(threadId);
|
|
@@ -967,9 +967,11 @@ function mapAgentNativeEvent(raw, input) {
|
|
|
967
967
|
reason: ev.connectionReason ?? "connect",
|
|
968
968
|
appId: ev.appId,
|
|
969
969
|
detail: ev.detail,
|
|
970
|
-
source: ev.
|
|
971
|
-
? {
|
|
972
|
-
:
|
|
970
|
+
source: ev.source
|
|
971
|
+
? { ...ev.source, kind: ev.source.kind ?? "connection" }
|
|
972
|
+
: ev.agent
|
|
973
|
+
? { id: ev.agent, kind: "agent", label: ev.agent }
|
|
974
|
+
: undefined,
|
|
973
975
|
},
|
|
974
976
|
];
|
|
975
977
|
}
|
package/dist/client/i18n.d.ts
CHANGED
|
@@ -67,7 +67,9 @@ export declare function useIconPickerLabels(): {
|
|
|
67
67
|
allCategories: string;
|
|
68
68
|
loadError: string;
|
|
69
69
|
saveError: string;
|
|
70
|
+
uploadFailed: string;
|
|
70
71
|
uploadTooLarge: string;
|
|
72
|
+
uploadUnsupportedType: string;
|
|
71
73
|
retry: string;
|
|
72
74
|
uploadHint: string;
|
|
73
75
|
colorNames: {
|
package/dist/client/i18n.js
CHANGED
|
@@ -488,7 +488,9 @@ export function useIconPickerLabels() {
|
|
|
488
488
|
allCategories: t("iconPicker.allCategories"),
|
|
489
489
|
loadError: t("iconPicker.loadError"),
|
|
490
490
|
saveError: t("iconPicker.saveError"),
|
|
491
|
+
uploadFailed: t("iconPicker.uploadFailed"),
|
|
491
492
|
uploadTooLarge: t("iconPicker.uploadTooLarge"),
|
|
493
|
+
uploadUnsupportedType: t("iconPicker.uploadUnsupportedType"),
|
|
492
494
|
retry: t("iconPicker.retry"),
|
|
493
495
|
uploadHint: t("iconPicker.uploadHint"),
|
|
494
496
|
colorNames: Object.fromEntries(Object.keys(defaultEnglishMessages.iconPicker.colorNames).map((color) => [
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { startWorkspaceProviderOAuth, workspaceProviderOAuthUrl, type WorkspaceProviderOAuthOptions, type WorkspaceProviderOAuthScope, } from "./workspace-provider-oauth.js";
|
|
2
|
+
export { getWorkspaceConnectionProvider } from "../../connections/catalog.js";
|
|
2
3
|
export { channelConnectionState, hasMissingRequiredCredentials, listChannelsForSettings, type ChannelConnectionState, type ChannelCredential, } from "./channel-setup.js";
|
|
3
4
|
export { useIntegrationStatus } from "./useIntegrationStatus.js";
|
|
4
5
|
export type { IntegrationStatus } from "./useIntegrationStatus.js";
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { startWorkspaceProviderOAuth, workspaceProviderOAuthUrl, } from "./workspace-provider-oauth.js";
|
|
2
|
+
export { getWorkspaceConnectionProvider } from "../../connections/catalog.js";
|
|
2
3
|
export { channelConnectionState, hasMissingRequiredCredentials, listChannelsForSettings, } from "./channel-setup.js";
|
|
3
4
|
export { useIntegrationStatus } from "./useIntegrationStatus.js";
|
|
4
5
|
export { listIntegrationEnvStatuses, listIntegrationStatuses, saveIntegrationEnvVars, setIntegrationEnabled, setupIntegration, disconnectManagedIntegrationInstallation, listManagedIntegrationInstallations, managedIntegrationOAuthUrl, managedSlackAgentManifestUrl, listManagedIntegrationScopes, saveManagedIntegrationScope, listManagedIntegrationBudgets, listManagedIntegrationMemory, forgetManagedIntegrationMemory, saveManagedIntegrationBudget, testManagedIntegrationInstallation, IntegrationClientError, } from "./api.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { useLab, useLabState, useLabs, type LabReference, type LabValues, } from "./use-lab.js";
|
|
1
|
+
export { useLab, useLabState, useLabs, type LabReference, type LabValues, type LabStates, } from "./use-lab.js";
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { LabDefinition } from "../../labs/registry.js";
|
|
2
|
+
import type { UserLabState } from "../../labs/store.js";
|
|
2
3
|
export type LabValues = Record<string, boolean>;
|
|
4
|
+
export type LabStates = Record<string, UserLabState>;
|
|
3
5
|
/**
|
|
4
6
|
* A lab by key, or by its definition. Pass the definition so the lab reads as
|
|
5
7
|
* its `defaultEnabled` until the server answers (and when it can't); a bare
|
|
@@ -8,6 +10,9 @@ export type LabValues = Record<string, boolean>;
|
|
|
8
10
|
export type LabReference = string | Pick<LabDefinition, "key" | "defaultEnabled">;
|
|
9
11
|
export declare function useLabState(lab: LabReference): {
|
|
10
12
|
enabled: boolean;
|
|
13
|
+
source: UserLabState["source"] | null;
|
|
14
|
+
mixed: boolean;
|
|
15
|
+
legacyValues?: Record<string, boolean>;
|
|
11
16
|
isLoading: boolean;
|
|
12
17
|
isError: boolean;
|
|
13
18
|
isSuccess: boolean;
|
|
@@ -6,13 +6,17 @@ function labKey(lab) {
|
|
|
6
6
|
export function useLabState(lab) {
|
|
7
7
|
const key = labKey(lab);
|
|
8
8
|
const { status } = useSession();
|
|
9
|
-
const query = useActionQuery("get-
|
|
9
|
+
const query = useActionQuery("get-lab-states", undefined, {
|
|
10
10
|
enabled: status === "authenticated",
|
|
11
11
|
});
|
|
12
|
+
const state = query.data?.[key];
|
|
12
13
|
return {
|
|
13
|
-
enabled:
|
|
14
|
-
?
|
|
14
|
+
enabled: state
|
|
15
|
+
? state.enabled
|
|
15
16
|
: typeof lab !== "string" && lab.defaultEnabled === true,
|
|
17
|
+
source: state?.source ?? null,
|
|
18
|
+
mixed: state?.mixed ?? false,
|
|
19
|
+
legacyValues: state?.legacyValues,
|
|
16
20
|
isLoading: query.isLoading || (status === "loading" && query.data === undefined),
|
|
17
21
|
isError: query.isError,
|
|
18
22
|
isSuccess: query.isSuccess,
|
|
@@ -2,14 +2,16 @@ export interface McpConnectionResumeRequest {
|
|
|
2
2
|
message: string;
|
|
3
3
|
returnUrl: string;
|
|
4
4
|
createdAt: number;
|
|
5
|
+
completionId?: string;
|
|
5
6
|
agentKit?: {
|
|
6
7
|
threadId: string;
|
|
7
8
|
runId: string;
|
|
8
9
|
requestId: string;
|
|
9
10
|
};
|
|
10
11
|
}
|
|
11
|
-
export declare function saveMcpConnectionResume(message: string, agentKit?: McpConnectionResumeRequest["agentKit"]): boolean;
|
|
12
|
-
export declare function
|
|
12
|
+
export declare function saveMcpConnectionResume(message: string, agentKit?: McpConnectionResumeRequest["agentKit"], completionId?: string): boolean;
|
|
13
|
+
export declare function getPendingMcpConnectionResume(returnUrl?: string): McpConnectionResumeRequest | null;
|
|
14
|
+
export declare function clearMcpConnectionResume(expected?: McpConnectionResumeRequest | string): void;
|
|
13
15
|
export declare function consumeMcpConnectionResume(returnUrl?: string): McpConnectionResumeRequest | null;
|
|
14
|
-
export declare function notifyMcpConnectionComplete(): void;
|
|
16
|
+
export declare function notifyMcpConnectionComplete(completionId?: string): void;
|
|
15
17
|
export declare function addMcpConnectionCompleteListener(listener: () => void): () => void;
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
const MCP_CONNECTION_RESUME_STORAGE_KEY = "agent-native:mcp-connection-resume";
|
|
2
2
|
const MCP_CONNECTION_RESUME_EVENT = "agent-native:mcp-connection-complete";
|
|
3
|
+
const MCP_CONNECTION_RESUME_COMPLETION_STORAGE_PREFIX = "agent-native:mcp-connection-completion:";
|
|
3
4
|
const MCP_CONNECTION_RESUME_TTL_MS = 10 * 60 * 1_000;
|
|
4
5
|
const MCP_CONNECTION_RESUME_MAX_MESSAGE_LENGTH = 24_000;
|
|
6
|
+
const completedResumeIds = new Set();
|
|
5
7
|
function currentReturnUrl() {
|
|
6
8
|
if (typeof window === "undefined")
|
|
7
9
|
return "/";
|
|
@@ -17,7 +19,27 @@ function getSessionStorage() {
|
|
|
17
19
|
return null;
|
|
18
20
|
}
|
|
19
21
|
}
|
|
20
|
-
|
|
22
|
+
function getLocalStorage() {
|
|
23
|
+
if (typeof window === "undefined")
|
|
24
|
+
return null;
|
|
25
|
+
try {
|
|
26
|
+
return window.localStorage;
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
// coercion-ok: callers fail closed when local storage is unavailable.
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function clearCompletionMarker(completionId) {
|
|
34
|
+
completedResumeIds.delete(completionId);
|
|
35
|
+
try {
|
|
36
|
+
getLocalStorage()?.removeItem(MCP_CONNECTION_RESUME_COMPLETION_STORAGE_PREFIX + completionId);
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
// coercion-ok: stale markers cannot complete the newer opaque attempt.
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
export function saveMcpConnectionResume(message, agentKit, completionId) {
|
|
21
43
|
const trimmedMessage = message.trim();
|
|
22
44
|
if (!trimmedMessage ||
|
|
23
45
|
trimmedMessage.length > MCP_CONNECTION_RESUME_MAX_MESSAGE_LENGTH) {
|
|
@@ -30,28 +52,57 @@ export function saveMcpConnectionResume(message, agentKit) {
|
|
|
30
52
|
message: trimmedMessage,
|
|
31
53
|
returnUrl: currentReturnUrl(),
|
|
32
54
|
createdAt: Date.now(),
|
|
55
|
+
...(completionId ? { completionId } : {}),
|
|
33
56
|
...(agentKit ? { agentKit } : {}),
|
|
34
57
|
};
|
|
58
|
+
const previousCompletionId = readStoredMcpConnectionResume()?.completionId;
|
|
35
59
|
try {
|
|
36
60
|
storage.setItem(MCP_CONNECTION_RESUME_STORAGE_KEY, JSON.stringify(request));
|
|
37
|
-
return true;
|
|
38
61
|
}
|
|
39
62
|
catch {
|
|
40
63
|
return false;
|
|
41
64
|
}
|
|
65
|
+
if (previousCompletionId)
|
|
66
|
+
clearCompletionMarker(previousCompletionId);
|
|
67
|
+
return true;
|
|
42
68
|
}
|
|
43
|
-
|
|
69
|
+
function removeStoredMcpConnectionResume(completionId) {
|
|
44
70
|
const storage = getSessionStorage();
|
|
45
71
|
if (!storage)
|
|
46
72
|
return;
|
|
73
|
+
let storedCompletionId;
|
|
74
|
+
let raw;
|
|
75
|
+
try {
|
|
76
|
+
raw = storage.getItem(MCP_CONNECTION_RESUME_STORAGE_KEY);
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
if (raw) {
|
|
82
|
+
try {
|
|
83
|
+
const request = JSON.parse(raw);
|
|
84
|
+
if (typeof request.completionId === "string") {
|
|
85
|
+
storedCompletionId = request.completionId;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
// coercion-ok: malformed records are removed below and cannot be resumed.
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
if (completionId && storedCompletionId !== completionId)
|
|
93
|
+
return;
|
|
47
94
|
try {
|
|
48
95
|
storage.removeItem(MCP_CONNECTION_RESUME_STORAGE_KEY);
|
|
49
96
|
}
|
|
50
97
|
catch {
|
|
51
|
-
//
|
|
98
|
+
// Keep its completion marker so a readable request can still be retried.
|
|
99
|
+
return;
|
|
52
100
|
}
|
|
101
|
+
const completedId = completionId ?? storedCompletionId;
|
|
102
|
+
if (completedId)
|
|
103
|
+
clearCompletionMarker(completedId);
|
|
53
104
|
}
|
|
54
|
-
|
|
105
|
+
function readStoredMcpConnectionResume() {
|
|
55
106
|
const storage = getSessionStorage();
|
|
56
107
|
if (!storage)
|
|
57
108
|
return null;
|
|
@@ -63,14 +114,16 @@ export function consumeMcpConnectionResume(returnUrl = currentReturnUrl()) {
|
|
|
63
114
|
request = JSON.parse(raw);
|
|
64
115
|
}
|
|
65
116
|
catch {
|
|
66
|
-
|
|
117
|
+
removeStoredMcpConnectionResume();
|
|
67
118
|
return null;
|
|
68
119
|
}
|
|
69
120
|
if (!request ||
|
|
70
121
|
typeof request.message !== "string" ||
|
|
71
122
|
typeof request.returnUrl !== "string" ||
|
|
72
|
-
typeof request.createdAt !== "number"
|
|
73
|
-
|
|
123
|
+
typeof request.createdAt !== "number" ||
|
|
124
|
+
(request.completionId !== undefined &&
|
|
125
|
+
(typeof request.completionId !== "string" || !request.completionId))) {
|
|
126
|
+
removeStoredMcpConnectionResume();
|
|
74
127
|
return null;
|
|
75
128
|
}
|
|
76
129
|
if (request.agentKit !== undefined &&
|
|
@@ -81,26 +134,110 @@ export function consumeMcpConnectionResume(returnUrl = currentReturnUrl()) {
|
|
|
81
134
|
!request.agentKit.runId.trim() ||
|
|
82
135
|
typeof request.agentKit.requestId !== "string" ||
|
|
83
136
|
!request.agentKit.requestId.trim())) {
|
|
84
|
-
|
|
137
|
+
removeStoredMcpConnectionResume();
|
|
85
138
|
return null;
|
|
86
139
|
}
|
|
87
140
|
if (Date.now() - request.createdAt > MCP_CONNECTION_RESUME_TTL_MS) {
|
|
88
|
-
|
|
141
|
+
removeStoredMcpConnectionResume();
|
|
89
142
|
return null;
|
|
90
143
|
}
|
|
144
|
+
return request;
|
|
145
|
+
}
|
|
146
|
+
function isCompletionRecorded(completionId) {
|
|
147
|
+
if (completedResumeIds.has(completionId))
|
|
148
|
+
return true;
|
|
149
|
+
const storage = getLocalStorage();
|
|
150
|
+
if (!storage)
|
|
151
|
+
return false;
|
|
152
|
+
try {
|
|
153
|
+
return (storage.getItem(MCP_CONNECTION_RESUME_COMPLETION_STORAGE_PREFIX + completionId) === "1");
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
// coercion-ok: unreadable completion state fails closed and keeps the request pending.
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
export function getPendingMcpConnectionResume(returnUrl = currentReturnUrl()) {
|
|
161
|
+
const request = readStoredMcpConnectionResume();
|
|
162
|
+
if (!request)
|
|
163
|
+
return null;
|
|
91
164
|
if (request.returnUrl !== returnUrl)
|
|
92
165
|
return null;
|
|
93
|
-
|
|
166
|
+
if (request.completionId && !isCompletionRecorded(request.completionId)) {
|
|
167
|
+
return null;
|
|
168
|
+
}
|
|
94
169
|
return request;
|
|
95
170
|
}
|
|
96
|
-
export function
|
|
171
|
+
export function clearMcpConnectionResume(expected) {
|
|
172
|
+
const current = readStoredMcpConnectionResume();
|
|
173
|
+
if (typeof expected === "string" && current?.completionId !== expected) {
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
if (expected &&
|
|
177
|
+
typeof expected !== "string" &&
|
|
178
|
+
(!current ||
|
|
179
|
+
current.createdAt !== expected.createdAt ||
|
|
180
|
+
current.returnUrl !== expected.returnUrl ||
|
|
181
|
+
current.message !== expected.message ||
|
|
182
|
+
current.completionId !== expected.completionId ||
|
|
183
|
+
current.agentKit?.threadId !== expected.agentKit?.threadId ||
|
|
184
|
+
current.agentKit?.runId !== expected.agentKit?.runId ||
|
|
185
|
+
current.agentKit?.requestId !== expected.agentKit?.requestId)) {
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
removeStoredMcpConnectionResume(typeof expected === "string" ? expected : current?.completionId);
|
|
189
|
+
}
|
|
190
|
+
export function consumeMcpConnectionResume(returnUrl = currentReturnUrl()) {
|
|
191
|
+
const request = getPendingMcpConnectionResume(returnUrl);
|
|
192
|
+
if (request)
|
|
193
|
+
clearMcpConnectionResume(request);
|
|
194
|
+
return request;
|
|
195
|
+
}
|
|
196
|
+
export function notifyMcpConnectionComplete(completionId) {
|
|
97
197
|
if (typeof window === "undefined")
|
|
98
198
|
return;
|
|
199
|
+
if (completionId) {
|
|
200
|
+
const request = readStoredMcpConnectionResume();
|
|
201
|
+
if (request?.completionId !== completionId)
|
|
202
|
+
return;
|
|
203
|
+
completedResumeIds.add(completionId);
|
|
204
|
+
try {
|
|
205
|
+
getLocalStorage()?.setItem(MCP_CONNECTION_RESUME_COMPLETION_STORAGE_PREFIX + completionId, "1");
|
|
206
|
+
}
|
|
207
|
+
catch {
|
|
208
|
+
// coercion-ok: the active page can use this signal; reloads fail closed.
|
|
209
|
+
}
|
|
210
|
+
}
|
|
99
211
|
window.dispatchEvent(new Event(MCP_CONNECTION_RESUME_EVENT));
|
|
100
212
|
}
|
|
101
213
|
export function addMcpConnectionCompleteListener(listener) {
|
|
102
214
|
if (typeof window === "undefined")
|
|
103
215
|
return () => { };
|
|
216
|
+
const onStorage = (event) => {
|
|
217
|
+
if (event.key?.startsWith(MCP_CONNECTION_RESUME_COMPLETION_STORAGE_PREFIX) &&
|
|
218
|
+
event.newValue !== null) {
|
|
219
|
+
listener();
|
|
220
|
+
}
|
|
221
|
+
};
|
|
222
|
+
const onMessage = (event) => {
|
|
223
|
+
if (event.origin !== window.location.origin ||
|
|
224
|
+
typeof event.data !== "object" ||
|
|
225
|
+
event.data === null ||
|
|
226
|
+
!("type" in event.data) ||
|
|
227
|
+
event.data.type !== "agent-native:workspace-connection-complete" ||
|
|
228
|
+
!("completionId" in event.data) ||
|
|
229
|
+
typeof event.data.completionId !== "string" ||
|
|
230
|
+
!event.source) {
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
notifyMcpConnectionComplete(event.data.completionId);
|
|
234
|
+
};
|
|
104
235
|
window.addEventListener(MCP_CONNECTION_RESUME_EVENT, listener);
|
|
105
|
-
|
|
236
|
+
window.addEventListener("storage", onStorage);
|
|
237
|
+
window.addEventListener("message", onMessage);
|
|
238
|
+
return () => {
|
|
239
|
+
window.removeEventListener(MCP_CONNECTION_RESUME_EVENT, listener);
|
|
240
|
+
window.removeEventListener("storage", onStorage);
|
|
241
|
+
window.removeEventListener("message", onMessage);
|
|
242
|
+
};
|
|
106
243
|
}
|
|
@@ -108,6 +108,12 @@ export interface SSEEvent {
|
|
|
108
108
|
provider?: string;
|
|
109
109
|
connectionReason?: "connect" | "grant" | "reauthorize" | "admin_required";
|
|
110
110
|
appId?: string;
|
|
111
|
+
source?: {
|
|
112
|
+
id: string;
|
|
113
|
+
kind?: string;
|
|
114
|
+
label?: string;
|
|
115
|
+
uri?: string;
|
|
116
|
+
};
|
|
111
117
|
error?: string;
|
|
112
118
|
message?: string;
|
|
113
119
|
seq?: number;
|
|
@@ -2,3 +2,4 @@ export { uploadEditorImage, type EditorImageUploadFn, type EditorImageUploadResu
|
|
|
2
2
|
export { useUploadResource } from "./use-upload-resource.js";
|
|
3
3
|
export { useFileUploadStatus } from "./use-file-upload-status.js";
|
|
4
4
|
export { fetchFileUploadStatus } from "../client-status-requests.js";
|
|
5
|
+
export { uploadWorkspacePrivateIcon, workspacePrivateIconLibraryUrl, workspacePrivateIconUrl, } from "./private-icon.js";
|
|
@@ -2,3 +2,4 @@ export { uploadEditorImage, } from "./upload-editor-image.js";
|
|
|
2
2
|
export { useUploadResource } from "./use-upload-resource.js";
|
|
3
3
|
export { useFileUploadStatus } from "./use-file-upload-status.js";
|
|
4
4
|
export { fetchFileUploadStatus } from "../client-status-requests.js";
|
|
5
|
+
export { uploadWorkspacePrivateIcon, workspacePrivateIconLibraryUrl, workspacePrivateIconUrl, } from "./private-icon.js";
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { IconValue } from "../../icons/index.js";
|
|
2
|
+
export declare function workspacePrivateIconUrl(orgId: string, image: Extract<IconValue, {
|
|
3
|
+
kind: "image";
|
|
4
|
+
}>): string | undefined;
|
|
5
|
+
export declare function workspacePrivateIconLibraryUrl(orgId: string, image: Extract<IconValue, {
|
|
6
|
+
kind: "image";
|
|
7
|
+
}>): string | undefined;
|
|
8
|
+
export declare function uploadWorkspacePrivateIcon(file: File): Promise<Extract<IconValue, {
|
|
9
|
+
kind: "image";
|
|
10
|
+
}>>;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { agentNativePath } from "../api-path.js";
|
|
2
|
+
export function workspacePrivateIconUrl(orgId, image) {
|
|
3
|
+
if (image.authority === "url")
|
|
4
|
+
return image.assetId;
|
|
5
|
+
if (image.authority !== "private-icon" || !orgId)
|
|
6
|
+
return undefined;
|
|
7
|
+
return agentNativePath(`/_agent-native/org/private-icons/${encodeURIComponent(orgId)}/${encodeURIComponent(image.assetId)}`);
|
|
8
|
+
}
|
|
9
|
+
export function workspacePrivateIconLibraryUrl(orgId, image) {
|
|
10
|
+
if (image.authority === "url")
|
|
11
|
+
return image.assetId;
|
|
12
|
+
if (image.authority !== "private-icon" || !orgId)
|
|
13
|
+
return undefined;
|
|
14
|
+
return agentNativePath(`/_agent-native/org/private-icons/library/${encodeURIComponent(orgId)}/${encodeURIComponent(image.assetId)}`);
|
|
15
|
+
}
|
|
16
|
+
export async function uploadWorkspacePrivateIcon(file) {
|
|
17
|
+
const form = new FormData();
|
|
18
|
+
form.set("file", file);
|
|
19
|
+
const response = await fetch(agentNativePath("/_agent-native/org/private-icons"), {
|
|
20
|
+
method: "POST",
|
|
21
|
+
credentials: "include",
|
|
22
|
+
body: form,
|
|
23
|
+
});
|
|
24
|
+
if (!response.ok) {
|
|
25
|
+
const body = response.headers
|
|
26
|
+
.get("content-type")
|
|
27
|
+
?.includes("application/json")
|
|
28
|
+
? await response.json()
|
|
29
|
+
: null;
|
|
30
|
+
const message = body &&
|
|
31
|
+
typeof body === "object" &&
|
|
32
|
+
"message" in body &&
|
|
33
|
+
typeof body.message === "string"
|
|
34
|
+
? body.message
|
|
35
|
+
: `Workspace icon upload failed (${response.status}).`;
|
|
36
|
+
throw new Error(message);
|
|
37
|
+
}
|
|
38
|
+
const body = await response.json();
|
|
39
|
+
if (!body ||
|
|
40
|
+
typeof body !== "object" ||
|
|
41
|
+
!("id" in body) ||
|
|
42
|
+
typeof body.id !== "string") {
|
|
43
|
+
throw new Error("Workspace icon upload returned an invalid asset ID.");
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
version: 1,
|
|
47
|
+
kind: "image",
|
|
48
|
+
authority: "private-icon",
|
|
49
|
+
assetId: body.id,
|
|
50
|
+
alt: file.name.replace(/\.[^./\\]+$/, ""),
|
|
51
|
+
};
|
|
52
|
+
}
|
package/dist/collab/routes.d.ts
CHANGED
|
@@ -8,16 +8,16 @@ export declare const getCollabState: import("h3").EventHandlerWithFetch<import("
|
|
|
8
8
|
state: string;
|
|
9
9
|
}>>;
|
|
10
10
|
export declare const postCollabUpdate: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
11
|
-
error: string;
|
|
12
11
|
ok?: undefined;
|
|
12
|
+
error: string;
|
|
13
13
|
} | {
|
|
14
14
|
error?: undefined;
|
|
15
15
|
ok: boolean;
|
|
16
16
|
}>>;
|
|
17
17
|
export declare const postCollabText: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
18
18
|
ok?: undefined;
|
|
19
|
-
error: string;
|
|
20
19
|
text?: undefined;
|
|
20
|
+
error: string;
|
|
21
21
|
} | {
|
|
22
22
|
error?: undefined;
|
|
23
23
|
ok: boolean;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { defineAction } from "../../action.js";
|
|
3
|
+
import { getLabForLegacyFlag } from "../../labs/registry.js";
|
|
4
|
+
import { getUserLabStates } from "../../labs/store.js";
|
|
3
5
|
import { captureError } from "../../server/capture-error.js";
|
|
4
6
|
import { listFeatureFlags } from "../registry.js";
|
|
5
7
|
import { defaultFeatureFlagRules, evaluateFeatureFlagRules, getFeatureFlagRules, getFeatureFlagRulesForKeys, } from "../store.js";
|
|
@@ -38,6 +40,24 @@ export default defineAction({
|
|
|
38
40
|
return [key, false];
|
|
39
41
|
}
|
|
40
42
|
}));
|
|
43
|
+
const migratedKeys = definitions
|
|
44
|
+
.map(({ key }) => key)
|
|
45
|
+
.filter((key) => getLabForLegacyFlag(key));
|
|
46
|
+
if (migratedKeys.length === 0 || !scope.userEmail)
|
|
47
|
+
return values;
|
|
48
|
+
const labStates = await getUserLabStates(scope.userEmail, scope);
|
|
49
|
+
for (const key of migratedKeys) {
|
|
50
|
+
const lab = getLabForLegacyFlag(key);
|
|
51
|
+
if (!lab)
|
|
52
|
+
continue;
|
|
53
|
+
const state = labStates[lab.key];
|
|
54
|
+
if (!state)
|
|
55
|
+
throw new Error(`Missing migrated lab state: ${lab.key}`);
|
|
56
|
+
values[key] =
|
|
57
|
+
state.source === "choice"
|
|
58
|
+
? state.enabled
|
|
59
|
+
: (state.legacyValues?.[key] ?? false);
|
|
60
|
+
}
|
|
41
61
|
return values;
|
|
42
62
|
},
|
|
43
63
|
});
|
|
@@ -19,6 +19,8 @@ declare const _default: import("../../action.js").ActionDefinition<Record<string
|
|
|
19
19
|
defaultValue?: false;
|
|
20
20
|
displayName?: string;
|
|
21
21
|
description?: string;
|
|
22
|
+
movedToLab: string;
|
|
23
|
+
canManage: boolean;
|
|
22
24
|
rules: import("../store.js").FeatureFlagRules;
|
|
23
25
|
enabledForCurrentUser: boolean;
|
|
24
26
|
}[];
|