@agent-native/core 0.105.0 → 0.106.1
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/corpus/README.md +2 -2
- package/corpus/core/CHANGELOG.md +39 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/application-state/index.ts +2 -0
- package/corpus/core/src/application-state/script-helpers.ts +12 -0
- package/corpus/core/src/application-state/store.ts +38 -0
- package/corpus/core/src/client/AssistantChat.tsx +4 -0
- package/corpus/core/src/client/MultiTabAssistantChat.tsx +5 -1
- package/corpus/core/src/client/composer/PromptComposer.tsx +8 -0
- package/corpus/core/src/client/composer/TiptapComposer.tsx +38 -1
- package/corpus/core/src/client/resources/McpIntegrationDialog.tsx +107 -32
- package/corpus/core/src/client/resources/mcp-integration-catalog.ts +33 -0
- package/corpus/core/src/client/resources/use-mcp-servers.ts +1 -0
- package/corpus/core/src/client/review/ReviewCommentComposer.tsx +10 -3
- package/corpus/core/src/client/use-chat-models.ts +10 -2
- package/corpus/core/src/connections/catalog.ts +107 -6
- package/corpus/core/src/localization/default-messages.ts +2 -0
- package/corpus/core/src/mcp/actions/call-mcp-tool.ts +18 -0
- package/corpus/core/src/mcp/actions/list-mcp-tools.ts +18 -0
- package/corpus/core/src/mcp-client/app-api.ts +136 -0
- package/corpus/core/src/mcp-client/index.ts +21 -0
- package/corpus/core/src/mcp-client/oauth-client.ts +462 -0
- package/corpus/core/src/mcp-client/oauth-routes.ts +307 -0
- package/corpus/core/src/mcp-client/remote-store.ts +93 -118
- package/corpus/core/src/mcp-client/remote-url.ts +97 -0
- package/corpus/core/src/mcp-client/routes.ts +11 -0
- package/corpus/core/src/oauth-tokens/store.ts +10 -4
- package/corpus/core/src/provider-api/index.ts +690 -55
- package/corpus/core/src/secrets/register-framework-secrets.ts +30 -0
- package/corpus/core/src/server/action-discovery.ts +2 -0
- package/corpus/core/src/server/core-routes-plugin.ts +9 -1
- package/corpus/core/src/server/workspace-provider-oauth.ts +448 -61
- package/corpus/core/src/templates/default/AGENTS.md +9 -7
- package/corpus/core/src/templates/workspace-core/.agents/skills/external-agents/SKILL.md +46 -0
- package/corpus/templates/analytics/app/lib/data-source-status.ts +2 -0
- package/corpus/templates/analytics/app/pages/DataSources.tsx +61 -0
- package/corpus/templates/analytics/server/handlers/jira.ts +7 -0
- package/corpus/templates/analytics/server/lib/jira.ts +14 -42
- package/corpus/templates/analytics/server/routes/api/test-connection.post.ts +11 -0
- package/corpus/templates/design/.agents/skills/visual-edit/SKILL.md +22 -0
- package/corpus/templates/design/AGENTS.md +16 -0
- package/corpus/templates/design/actions/cancel-node-rewrite-request.ts +54 -0
- package/corpus/templates/design/actions/propose-node-rewrite.ts +290 -0
- package/corpus/templates/design/actions/resolve-node-rewrite.ts +257 -0
- package/corpus/templates/design/actions/view-screen.ts +98 -2
- package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +71 -1
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +19 -0
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +33 -0
- package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +194 -0
- package/corpus/templates/design/app/components/design/bridge/hit-test.bridge.ts +21 -4
- package/corpus/templates/design/app/components/design/design-canvas/iframe-events.ts +18 -0
- package/corpus/templates/design/app/components/design/multi-screen/types.ts +4 -0
- package/corpus/templates/design/app/components/visual-editor/NodeRewriteProposal.tsx +638 -0
- package/corpus/templates/design/app/components/visual-editor/ReviewCanvasPins.tsx +535 -54
- package/corpus/templates/design/app/components/visual-editor/index.ts +5 -1
- package/corpus/templates/design/app/components/visual-editor/review-canvas-state.ts +21 -3
- package/corpus/templates/design/app/i18n/ar-SA.ts +35 -0
- package/corpus/templates/design/app/i18n/de-DE.ts +35 -0
- package/corpus/templates/design/app/i18n/es-ES.ts +35 -0
- package/corpus/templates/design/app/i18n/fr-FR.ts +35 -0
- package/corpus/templates/design/app/i18n/hi-IN.ts +35 -0
- package/corpus/templates/design/app/i18n/ja-JP.ts +35 -0
- package/corpus/templates/design/app/i18n/ko-KR.ts +35 -0
- package/corpus/templates/design/app/i18n/pt-BR.ts +35 -0
- package/corpus/templates/design/app/i18n/zh-CN.ts +35 -0
- package/corpus/templates/design/app/i18n/zh-TW.ts +32 -0
- package/corpus/templates/design/app/i18n-data.ts +32 -0
- package/corpus/templates/design/app/lib/node-reprompt.ts +110 -0
- package/corpus/templates/design/changelog/2026-07-16-design-editing-and-review-are-now-more-predictable.md +6 -0
- package/corpus/templates/design/server/lib/reprompt-action-guard.ts +107 -0
- package/corpus/templates/design/server/plugins/agent-chat.ts +9 -1
- package/corpus/templates/design/shared/code-layer.ts +15 -0
- package/corpus/templates/design/shared/node-rewrite.ts +213 -0
- package/corpus/templates/design/shared/review-anchor.ts +26 -3
- package/corpus/templates/dispatch/app/routes/integrations.tsx +57 -4
- package/dist/application-state/index.d.ts +2 -2
- package/dist/application-state/index.d.ts.map +1 -1
- package/dist/application-state/index.js +2 -2
- package/dist/application-state/index.js.map +1 -1
- package/dist/application-state/script-helpers.d.ts +1 -0
- package/dist/application-state/script-helpers.d.ts.map +1 -1
- package/dist/application-state/script-helpers.js +7 -1
- package/dist/application-state/script-helpers.js.map +1 -1
- package/dist/application-state/store.d.ts +1 -0
- package/dist/application-state/store.d.ts.map +1 -1
- package/dist/application-state/store.js +28 -0
- package/dist/application-state/store.js.map +1 -1
- package/dist/client/AssistantChat.d.ts +2 -0
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +2 -2
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
- package/dist/client/MultiTabAssistantChat.js +5 -2
- package/dist/client/MultiTabAssistantChat.js.map +1 -1
- package/dist/client/composer/PromptComposer.d.ts +2 -0
- package/dist/client/composer/PromptComposer.d.ts.map +1 -1
- package/dist/client/composer/PromptComposer.js +5 -2
- package/dist/client/composer/PromptComposer.js.map +1 -1
- package/dist/client/composer/TiptapComposer.d.ts +4 -1
- package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
- package/dist/client/composer/TiptapComposer.js +13 -5
- package/dist/client/composer/TiptapComposer.js.map +1 -1
- package/dist/client/resources/McpIntegrationDialog.d.ts.map +1 -1
- package/dist/client/resources/McpIntegrationDialog.js +58 -14
- package/dist/client/resources/McpIntegrationDialog.js.map +1 -1
- package/dist/client/resources/mcp-integration-catalog.d.ts +9 -0
- package/dist/client/resources/mcp-integration-catalog.d.ts.map +1 -1
- package/dist/client/resources/mcp-integration-catalog.js +13 -0
- package/dist/client/resources/mcp-integration-catalog.js.map +1 -1
- package/dist/client/resources/use-mcp-servers.d.ts +1 -0
- package/dist/client/resources/use-mcp-servers.d.ts.map +1 -1
- package/dist/client/resources/use-mcp-servers.js.map +1 -1
- package/dist/client/review/ReviewCommentComposer.d.ts +4 -1
- package/dist/client/review/ReviewCommentComposer.d.ts.map +1 -1
- package/dist/client/review/ReviewCommentComposer.js +3 -3
- package/dist/client/review/ReviewCommentComposer.js.map +1 -1
- package/dist/client/use-chat-models.d.ts +1 -0
- package/dist/client/use-chat-models.d.ts.map +1 -1
- package/dist/client/use-chat-models.js +8 -2
- package/dist/client/use-chat-models.js.map +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/connections/catalog.d.ts +78 -7
- package/dist/connections/catalog.d.ts.map +1 -1
- package/dist/connections/catalog.js +97 -6
- package/dist/connections/catalog.js.map +1 -1
- package/dist/localization/default-messages.d.ts +2 -0
- package/dist/localization/default-messages.d.ts.map +1 -1
- package/dist/localization/default-messages.js +2 -0
- package/dist/localization/default-messages.js.map +1 -1
- package/dist/mcp/actions/call-mcp-tool.d.ts +7 -0
- package/dist/mcp/actions/call-mcp-tool.d.ts.map +1 -0
- package/dist/mcp/actions/call-mcp-tool.js +15 -0
- package/dist/mcp/actions/call-mcp-tool.js.map +1 -0
- package/dist/mcp/actions/list-mcp-tools.d.ts +5 -0
- package/dist/mcp/actions/list-mcp-tools.d.ts.map +1 -0
- package/dist/mcp/actions/list-mcp-tools.js +16 -0
- package/dist/mcp/actions/list-mcp-tools.js.map +1 -0
- package/dist/mcp-client/app-api.d.ts +34 -0
- package/dist/mcp-client/app-api.d.ts.map +1 -0
- package/dist/mcp-client/app-api.js +94 -0
- package/dist/mcp-client/app-api.js.map +1 -0
- package/dist/mcp-client/index.d.ts +3 -1
- package/dist/mcp-client/index.d.ts.map +1 -1
- package/dist/mcp-client/index.js +3 -1
- package/dist/mcp-client/index.js.map +1 -1
- package/dist/mcp-client/oauth-client.d.ts +113 -0
- package/dist/mcp-client/oauth-client.d.ts.map +1 -0
- package/dist/mcp-client/oauth-client.js +316 -0
- package/dist/mcp-client/oauth-client.js.map +1 -0
- package/dist/mcp-client/oauth-routes.d.ts +25 -0
- package/dist/mcp-client/oauth-routes.d.ts.map +1 -0
- package/dist/mcp-client/oauth-routes.js +218 -0
- package/dist/mcp-client/oauth-routes.js.map +1 -0
- package/dist/mcp-client/remote-store.d.ts +21 -6
- package/dist/mcp-client/remote-store.d.ts.map +1 -1
- package/dist/mcp-client/remote-store.js +72 -124
- package/dist/mcp-client/remote-store.js.map +1 -1
- package/dist/mcp-client/remote-url.d.ts +8 -0
- package/dist/mcp-client/remote-url.d.ts.map +1 -0
- package/dist/mcp-client/remote-url.js +103 -0
- package/dist/mcp-client/remote-url.js.map +1 -0
- package/dist/mcp-client/routes.d.ts +1 -0
- package/dist/mcp-client/routes.d.ts.map +1 -1
- package/dist/mcp-client/routes.js +9 -0
- package/dist/mcp-client/routes.js.map +1 -1
- package/dist/notifications/routes.d.ts +2 -2
- package/dist/oauth-tokens/store.d.ts +2 -2
- package/dist/oauth-tokens/store.d.ts.map +1 -1
- package/dist/oauth-tokens/store.js +10 -6
- package/dist/oauth-tokens/store.js.map +1 -1
- package/dist/observability/routes.d.ts +5 -5
- package/dist/provider-api/index.d.ts +14 -0
- package/dist/provider-api/index.d.ts.map +1 -1
- package/dist/provider-api/index.js +499 -61
- package/dist/provider-api/index.js.map +1 -1
- package/dist/secrets/register-framework-secrets.d.ts.map +1 -1
- package/dist/secrets/register-framework-secrets.js +28 -0
- package/dist/secrets/register-framework-secrets.js.map +1 -1
- package/dist/secrets/routes.d.ts +9 -9
- package/dist/server/action-discovery.d.ts.map +1 -1
- package/dist/server/action-discovery.js +2 -0
- package/dist/server/action-discovery.js.map +1 -1
- package/dist/server/core-routes-plugin.d.ts.map +1 -1
- package/dist/server/core-routes-plugin.js +9 -1
- package/dist/server/core-routes-plugin.js.map +1 -1
- package/dist/server/workspace-provider-oauth.d.ts +10 -3
- package/dist/server/workspace-provider-oauth.d.ts.map +1 -1
- package/dist/server/workspace-provider-oauth.js +325 -43
- package/dist/server/workspace-provider-oauth.js.map +1 -1
- package/dist/templates/default/AGENTS.md +9 -7
- package/dist/templates/workspace-core/.agents/skills/external-agents/SKILL.md +46 -0
- package/package.json +2 -2
- package/src/templates/default/AGENTS.md +9 -7
- package/src/templates/workspace-core/.agents/skills/external-agents/SKILL.md +46 -0
package/corpus/README.md
CHANGED
package/corpus/core/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,44 @@
|
|
|
1
1
|
# @agent-native/core
|
|
2
2
|
|
|
3
|
+
## 0.106.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 0d8118e: Allow review comment composers to render a custom agent action in the standard action row, choose the Enter-key submit target, and atomically compare-and-set application state for race-safe UI workflows.
|
|
8
|
+
|
|
9
|
+
## 0.106.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- a485fbe: Add the Creative Context package for importing, versioning, searching, and reusing workspace decks, designs, assets, websites, and content across creative apps.
|
|
14
|
+
|
|
15
|
+
Expose reusable ingestion, prompt-context provider, and search utility seams from core for package-driven creative context.
|
|
16
|
+
|
|
17
|
+
Includes bounded image-region cropping for durable localized creative-context fallbacks.
|
|
18
|
+
|
|
19
|
+
- a485fbe: Add one-click OAuth connections for standard remote MCP servers and shared workspace providers, including GitHub, Figma, Google Drive, HubSpot, Jira Cloud, Notion, and Sentry. OAuth credentials are encrypted and refreshed per user or organization without exposing tokens to browsers or MCP App iframes. Existing API-key and token credentials remain available as explicit fallbacks, and provider API requests can use an OAuth-backed workspace connection.
|
|
20
|
+
- a485fbe: Redesign the agent workspace with plain files first, dedicated resource collections, and a snapshots view for recent context inspection.
|
|
21
|
+
- a485fbe: Add public session replay context and timestamped Analytics links, support host-owned tracking identity, and allow Analytics replay pages to open at a requested timeline offset.
|
|
22
|
+
|
|
23
|
+
### Patch Changes
|
|
24
|
+
|
|
25
|
+
- a485fbe: Fail serverless builds that bundle Vitest test runtime code into production SSR output.
|
|
26
|
+
- a485fbe: Disable app-shell transitions across the shared AgentSidebar subtree while the sidebar is being resized.
|
|
27
|
+
- a485fbe: Count explicitly failed action tool events as errors in observability traces and summaries even when their result text does not start with `Error`.
|
|
28
|
+
- a485fbe: Fix managed Slack OAuth to resolve scoped app credentials within the signed-in request context.
|
|
29
|
+
- a485fbe: Show a skeleton while the agent chat model picker is loading its provider and model list.
|
|
30
|
+
- a485fbe: Render dashboard, form, and other resource context as a normal composer chip instead of a scoped-chat badge and history partition.
|
|
31
|
+
- a485fbe: Protect existing extension visual design during data-only repairs by requiring explicit intent for full-body replacements, stop deterministic edit failures before the agent retries the same arguments, and resume cleanly when a provider closes while an action input is still being assembled.
|
|
32
|
+
- a485fbe: Teach Plan agents to fence destructive edits against fresh plan revisions and verify persisted content before closing feedback.
|
|
33
|
+
- a485fbe: Inline `AgentChatSurface` and `AgentChatHome` instances now hide the legacy Chat/Workspace header and chat tab row by default.
|
|
34
|
+
- a485fbe: Share package-registered actions across runtime module instances and mount them alongside explicit app action registries.
|
|
35
|
+
- a485fbe: Hide sidebar chat tabs until a second chat is open so a lone chat does not show a “New chat” tab.
|
|
36
|
+
- a485fbe: Re-enable the sticky 80/20 Sonnet 5 versus GPT-5.6 Luna default-model experiment across first-party hosted templates.
|
|
37
|
+
- a485fbe: Avoid repeated desktop sidebar width transitions while the agent sidebar is being resized.
|
|
38
|
+
- a485fbe: Prevent duplicate recovery submissions and reject late worker events after an agent run has already reached a terminal state.
|
|
39
|
+
- Updated dependencies [a485fbe]
|
|
40
|
+
- @agent-native/recap-cli@0.4.4
|
|
41
|
+
|
|
3
42
|
## 0.105.0
|
|
4
43
|
|
|
5
44
|
### Minor Changes
|
package/corpus/core/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-native/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.106.1",
|
|
4
4
|
"description": "Framework for agent-native application development — where AI agents and UI share SQL state, actions, and context",
|
|
5
5
|
"homepage": "https://github.com/BuilderIO/agent-native#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -4,6 +4,7 @@ export {
|
|
|
4
4
|
appStateGetMany,
|
|
5
5
|
appStatePut,
|
|
6
6
|
appStateDelete,
|
|
7
|
+
appStateCompareAndSet,
|
|
7
8
|
appStateList,
|
|
8
9
|
appStateDeleteByPrefix,
|
|
9
10
|
} from "./store.js";
|
|
@@ -33,6 +34,7 @@ export {
|
|
|
33
34
|
readAppState,
|
|
34
35
|
writeAppState,
|
|
35
36
|
deleteAppState,
|
|
37
|
+
compareAndSetAppState,
|
|
36
38
|
listAppState,
|
|
37
39
|
deleteAppStateByPrefix,
|
|
38
40
|
readAppStateForCurrentTab,
|
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
appStateGet,
|
|
18
18
|
appStatePut,
|
|
19
19
|
appStateDelete,
|
|
20
|
+
appStateCompareAndSet,
|
|
20
21
|
appStateList,
|
|
21
22
|
appStateDeleteByPrefix,
|
|
22
23
|
} from "./store.js";
|
|
@@ -71,6 +72,17 @@ export async function deleteAppState(key: string): Promise<boolean> {
|
|
|
71
72
|
});
|
|
72
73
|
}
|
|
73
74
|
|
|
75
|
+
export async function compareAndSetAppState(
|
|
76
|
+
key: string,
|
|
77
|
+
expectedValue: Record<string, unknown>,
|
|
78
|
+
nextValue: Record<string, unknown> | null,
|
|
79
|
+
): Promise<boolean> {
|
|
80
|
+
const sessionId = await resolveSessionId();
|
|
81
|
+
return appStateCompareAndSet(sessionId, key, expectedValue, nextValue, {
|
|
82
|
+
requestSource: "agent",
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
|
|
74
86
|
export async function listAppState(
|
|
75
87
|
prefix: string,
|
|
76
88
|
): Promise<Array<{ key: string; value: Record<string, unknown> }>> {
|
|
@@ -191,6 +191,44 @@ export async function appStateDelete(
|
|
|
191
191
|
return deleted;
|
|
192
192
|
}
|
|
193
193
|
|
|
194
|
+
export async function appStateCompareAndSet(
|
|
195
|
+
sessionId: string,
|
|
196
|
+
key: string,
|
|
197
|
+
expectedValue: Record<string, unknown>,
|
|
198
|
+
nextValue: Record<string, unknown> | null,
|
|
199
|
+
options?: StoreWriteOptions,
|
|
200
|
+
): Promise<boolean> {
|
|
201
|
+
await ensureTable();
|
|
202
|
+
const client = getDbExec();
|
|
203
|
+
const expected = JSON.stringify(expectedValue);
|
|
204
|
+
if (nextValue === null) {
|
|
205
|
+
const result = await client.execute({
|
|
206
|
+
sql: `DELETE FROM application_state WHERE session_id = ? AND key = ? AND value = ?`,
|
|
207
|
+
args: [sessionId, key, expected],
|
|
208
|
+
});
|
|
209
|
+
const changed = result.rowsAffected > 0;
|
|
210
|
+
if (changed) emitAppStateDelete(key, options?.requestSource, sessionId);
|
|
211
|
+
return changed;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const next = JSON.stringify(nextValue);
|
|
215
|
+
if (
|
|
216
|
+
!isLocalDatabase() &&
|
|
217
|
+
Buffer.byteLength(next, "utf8") > MAX_HOSTED_APP_STATE_VALUE_BYTES
|
|
218
|
+
) {
|
|
219
|
+
throw new Error(
|
|
220
|
+
`application_state value "${key}" is too large for hosted SQL storage. Store large files, base64, or blobs in file storage and write only a URL or handle.`,
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
const result = await client.execute({
|
|
224
|
+
sql: `UPDATE application_state SET value = ?, updated_at = ? WHERE session_id = ? AND key = ? AND value = ?`,
|
|
225
|
+
args: [next, Date.now(), sessionId, key, expected],
|
|
226
|
+
});
|
|
227
|
+
const changed = result.rowsAffected > 0;
|
|
228
|
+
if (changed) emitAppStateChange(key, options?.requestSource, sessionId);
|
|
229
|
+
return changed;
|
|
230
|
+
}
|
|
231
|
+
|
|
194
232
|
export async function appStateList(
|
|
195
233
|
sessionId: string,
|
|
196
234
|
keyPrefix: string,
|
|
@@ -1800,6 +1800,8 @@ export interface AssistantChatProps {
|
|
|
1800
1800
|
models: string[];
|
|
1801
1801
|
configured: boolean;
|
|
1802
1802
|
}>;
|
|
1803
|
+
/** Whether the model list is still being resolved. */
|
|
1804
|
+
modelListLoading?: boolean;
|
|
1803
1805
|
/** Callback when user picks a model from the picker */
|
|
1804
1806
|
onModelChange?: (model: string, engine: string) => void;
|
|
1805
1807
|
/** Callback when user picks a reasoning effort from the picker */
|
|
@@ -2174,6 +2176,7 @@ const AssistantChatInner = forwardRef<
|
|
|
2174
2176
|
defaultModel,
|
|
2175
2177
|
selectedEffort,
|
|
2176
2178
|
availableModels,
|
|
2179
|
+
modelListLoading,
|
|
2177
2180
|
onModelChange,
|
|
2178
2181
|
onEffortChange,
|
|
2179
2182
|
imageModelMenu,
|
|
@@ -5531,6 +5534,7 @@ const AssistantChatInner = forwardRef<
|
|
|
5531
5534
|
selectedModel={selectedModel ?? defaultModel}
|
|
5532
5535
|
selectedEffort={selectedEffort}
|
|
5533
5536
|
availableModels={availableModels}
|
|
5537
|
+
modelListLoading={modelListLoading}
|
|
5534
5538
|
onModelChange={onModelChange}
|
|
5535
5539
|
onEffortChange={onEffortChange}
|
|
5536
5540
|
imageModelMenu={imageModelMenu}
|
|
@@ -911,6 +911,7 @@ export function MultiTabAssistantChat({
|
|
|
911
911
|
const [availableModels, setAvailableModels] = useState<EngineModelGroup[]>(
|
|
912
912
|
[],
|
|
913
913
|
);
|
|
914
|
+
const [modelListLoading, setModelListLoading] = useState(true);
|
|
914
915
|
const [defaultModel, setDefaultModel] = useState<string>(DEFAULT_MODEL);
|
|
915
916
|
const threadModelRef = useRef<
|
|
916
917
|
Map<string, { model: string; engine?: string; effort?: ReasoningEffort }>
|
|
@@ -1035,6 +1036,7 @@ export function MultiTabAssistantChat({
|
|
|
1035
1036
|
);
|
|
1036
1037
|
|
|
1037
1038
|
const refreshEngines = useCallback(() => {
|
|
1039
|
+
setModelListLoading(true);
|
|
1038
1040
|
Promise.all([
|
|
1039
1041
|
callAction("manage-agent-engine" as any, { action: "list" } as any).catch(
|
|
1040
1042
|
() => null,
|
|
@@ -1068,7 +1070,8 @@ export function MultiTabAssistantChat({
|
|
|
1068
1070
|
setAvailableModels(groups);
|
|
1069
1071
|
setDefaultModel(currentModel ?? DEFAULT_MODEL);
|
|
1070
1072
|
})
|
|
1071
|
-
.catch(() => {})
|
|
1073
|
+
.catch(() => {})
|
|
1074
|
+
.finally(() => setModelListLoading(false));
|
|
1072
1075
|
}, []);
|
|
1073
1076
|
|
|
1074
1077
|
useEffect(() => {
|
|
@@ -2522,6 +2525,7 @@ export function MultiTabAssistantChat({
|
|
|
2522
2525
|
composerSlot={props.composerSlot}
|
|
2523
2526
|
defaultModel={defaultModel}
|
|
2524
2527
|
availableModels={availableModels}
|
|
2528
|
+
modelListLoading={modelListLoading}
|
|
2525
2529
|
onModelChange={handleModelChange}
|
|
2526
2530
|
onEffortChange={handleEffortChange}
|
|
2527
2531
|
onForkChat={() => handleForkChat(tabId)}
|
|
@@ -136,6 +136,8 @@ export interface PromptComposerProps {
|
|
|
136
136
|
onSlashCommand?: (command: string) => void;
|
|
137
137
|
/** External model list for hosts that already resolve models outside the app. */
|
|
138
138
|
availableModels?: EngineModelGroup[];
|
|
139
|
+
/** Whether the external model list is still being resolved. */
|
|
140
|
+
modelListLoading?: boolean;
|
|
139
141
|
selectedModel?: string;
|
|
140
142
|
selectedEngine?: string;
|
|
141
143
|
selectedEffort?: ReasoningEffort;
|
|
@@ -468,6 +470,7 @@ function PromptComposerInner({
|
|
|
468
470
|
includeDefaultSlashSkills,
|
|
469
471
|
onSlashCommand,
|
|
470
472
|
availableModels,
|
|
473
|
+
modelListLoading,
|
|
471
474
|
selectedModel,
|
|
472
475
|
selectedEngine,
|
|
473
476
|
selectedEffort,
|
|
@@ -501,6 +504,10 @@ function PromptComposerInner({
|
|
|
501
504
|
const composerModelGroups = showModelSelector
|
|
502
505
|
? (availableModels ?? models.availableModels)
|
|
503
506
|
: undefined;
|
|
507
|
+
const composerModelListLoading =
|
|
508
|
+
showModelSelector &&
|
|
509
|
+
(modelListLoading ??
|
|
510
|
+
(availableModels ? availableModels.length === 0 : models.isLoading));
|
|
504
511
|
const handleModelChange = showModelSelector
|
|
505
512
|
? (onModelChange ?? models.onModelChange)
|
|
506
513
|
: undefined;
|
|
@@ -645,6 +652,7 @@ function PromptComposerInner({
|
|
|
645
652
|
selectedModel={composerModel}
|
|
646
653
|
selectedEffort={composerEffort}
|
|
647
654
|
availableModels={composerModelGroups}
|
|
655
|
+
modelListLoading={composerModelListLoading}
|
|
648
656
|
onModelChange={handleModelChange}
|
|
649
657
|
onEffortChange={handleEffortChange}
|
|
650
658
|
providerConnectStatusEnabled={resolvedModelStatusChecksEnabled}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Skeleton } from "@agent-native/toolkit/ui/skeleton";
|
|
1
2
|
import { useComposer, useComposerRuntime } from "@assistant-ui/react";
|
|
2
3
|
import {
|
|
3
4
|
IconArrowUp,
|
|
@@ -615,6 +616,8 @@ export interface TiptapComposerProps {
|
|
|
615
616
|
models: string[];
|
|
616
617
|
configured: boolean;
|
|
617
618
|
}>;
|
|
619
|
+
/** Whether the model list is still being resolved. */
|
|
620
|
+
modelListLoading?: boolean;
|
|
618
621
|
/** Callback when user picks a model */
|
|
619
622
|
onModelChange?: (model: string, engine: string) => void;
|
|
620
623
|
/** Callback when user picks a reasoning effort */
|
|
@@ -823,6 +826,13 @@ export const MODEL_SELECTOR_POPOVER_STYLE = {
|
|
|
823
826
|
maxHeight: "min(500px, var(--radix-popover-content-available-height, 500px))",
|
|
824
827
|
} satisfies React.CSSProperties;
|
|
825
828
|
|
|
829
|
+
export function shouldShowModelSelectorSkeleton(
|
|
830
|
+
isLoading: boolean,
|
|
831
|
+
engineCount: number,
|
|
832
|
+
): boolean {
|
|
833
|
+
return isLoading && engineCount === 0;
|
|
834
|
+
}
|
|
835
|
+
|
|
826
836
|
function friendlyModelName(model: string): string {
|
|
827
837
|
if (FRIENDLY_MODEL_NAMES[model]) return FRIENDLY_MODEL_NAMES[model];
|
|
828
838
|
// Claude: claude-{tier}-{major}[-minor][-dateYYYYMMDD] → Tier Major[.Minor]
|
|
@@ -950,6 +960,7 @@ function ModelSelector({
|
|
|
950
960
|
model,
|
|
951
961
|
effort = DEFAULT_REASONING_EFFORT,
|
|
952
962
|
engines,
|
|
963
|
+
modelListLoading = false,
|
|
953
964
|
onChange,
|
|
954
965
|
onEffortChange,
|
|
955
966
|
providerConnectStatusEnabled = true,
|
|
@@ -965,6 +976,7 @@ function ModelSelector({
|
|
|
965
976
|
models: string[];
|
|
966
977
|
configured: boolean;
|
|
967
978
|
}>;
|
|
979
|
+
modelListLoading?: boolean;
|
|
968
980
|
onChange: (model: string, engine: string) => void;
|
|
969
981
|
onEffortChange?: (effort: ReasoningEffort) => void;
|
|
970
982
|
providerConnectStatusEnabled?: boolean;
|
|
@@ -1034,6 +1046,10 @@ function ModelSelector({
|
|
|
1034
1046
|
const imageModelLabel =
|
|
1035
1047
|
imageModel?.options.find((option) => option.value === imageModel.value)
|
|
1036
1048
|
?.label ?? imageModel?.value;
|
|
1049
|
+
const showModelListSkeleton = shouldShowModelSelectorSkeleton(
|
|
1050
|
+
modelListLoading,
|
|
1051
|
+
engines.length,
|
|
1052
|
+
);
|
|
1037
1053
|
|
|
1038
1054
|
// When Builder.io isn't connected, surface a one-click connect path —
|
|
1039
1055
|
// it unlocks every model family (Claude, OpenAI, Gemini) without the
|
|
@@ -1200,6 +1216,7 @@ function ModelSelector({
|
|
|
1200
1216
|
<div className="my-1 border-t border-border" />
|
|
1201
1217
|
</>
|
|
1202
1218
|
)}
|
|
1219
|
+
{showModelListSkeleton && <ModelSelectorSkeleton />}
|
|
1203
1220
|
{autoModelGroup && (
|
|
1204
1221
|
<button
|
|
1205
1222
|
type="button"
|
|
@@ -1304,7 +1321,7 @@ function ModelSelector({
|
|
|
1304
1321
|
</div>
|
|
1305
1322
|
);
|
|
1306
1323
|
})}
|
|
1307
|
-
{effortOptions.length > 0 && (
|
|
1324
|
+
{!showModelListSkeleton && effortOptions.length > 0 && (
|
|
1308
1325
|
<>
|
|
1309
1326
|
<div className="my-1 border-t border-border" />
|
|
1310
1327
|
<div className="flex items-center hover:bg-accent/30">
|
|
@@ -1352,6 +1369,24 @@ function ModelSelector({
|
|
|
1352
1369
|
);
|
|
1353
1370
|
}
|
|
1354
1371
|
|
|
1372
|
+
function ModelSelectorSkeleton() {
|
|
1373
|
+
return (
|
|
1374
|
+
<div
|
|
1375
|
+
className="space-y-1 px-2 py-2"
|
|
1376
|
+
role="status"
|
|
1377
|
+
aria-label="Loading models"
|
|
1378
|
+
>
|
|
1379
|
+
<span className="sr-only">Loading models…</span>
|
|
1380
|
+
{["w-24", "w-32", "w-20", "w-28"].map((width, index) => (
|
|
1381
|
+
<div key={index} className="flex items-center gap-1.5 px-1 py-1.5">
|
|
1382
|
+
<Skeleton className="size-3 rounded-sm" />
|
|
1383
|
+
<Skeleton className={`h-3 ${width}`} />
|
|
1384
|
+
</div>
|
|
1385
|
+
))}
|
|
1386
|
+
</div>
|
|
1387
|
+
);
|
|
1388
|
+
}
|
|
1389
|
+
|
|
1355
1390
|
type PopoverState = {
|
|
1356
1391
|
type: "@" | "/";
|
|
1357
1392
|
position: { top: number; left: number };
|
|
@@ -1389,6 +1424,7 @@ export function TiptapComposer({
|
|
|
1389
1424
|
selectedModel,
|
|
1390
1425
|
selectedEffort,
|
|
1391
1426
|
availableModels,
|
|
1427
|
+
modelListLoading,
|
|
1392
1428
|
onModelChange,
|
|
1393
1429
|
onEffortChange,
|
|
1394
1430
|
providerConnectStatusEnabled,
|
|
@@ -2791,6 +2827,7 @@ export function TiptapComposer({
|
|
|
2791
2827
|
model={selectedModel}
|
|
2792
2828
|
effort={selectedEffort}
|
|
2793
2829
|
engines={availableModels}
|
|
2830
|
+
modelListLoading={modelListLoading}
|
|
2794
2831
|
onChange={onModelChange}
|
|
2795
2832
|
onEffortChange={onEffortChange}
|
|
2796
2833
|
providerConnectStatusEnabled={providerConnectStatusEnabled}
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
} from "@tabler/icons-react";
|
|
8
8
|
import { useEffect, useMemo, useRef, useState } from "react";
|
|
9
9
|
|
|
10
|
+
import { agentNativePath } from "../api-path.js";
|
|
10
11
|
import {
|
|
11
12
|
Dialog,
|
|
12
13
|
DialogContent,
|
|
@@ -22,10 +23,12 @@ import {
|
|
|
22
23
|
import { useT } from "../i18n.js";
|
|
23
24
|
import { cn } from "../utils.js";
|
|
24
25
|
import {
|
|
26
|
+
buildMcpOAuthStartUrl,
|
|
25
27
|
createMcpIntegrationFormDefaults,
|
|
26
28
|
filterMcpIntegrations,
|
|
27
29
|
getDefaultMcpIntegrations,
|
|
28
30
|
isCustomMcpIntegrationEnabled,
|
|
31
|
+
resolveMcpIntegrationScope,
|
|
29
32
|
type DefaultMcpIntegration,
|
|
30
33
|
} from "./mcp-integration-catalog.js";
|
|
31
34
|
import {
|
|
@@ -92,7 +95,12 @@ export function McpIntegrationDialog({
|
|
|
92
95
|
const [mode, setMode] = useState<DialogMode>("catalog");
|
|
93
96
|
const [query, setQuery] = useState("");
|
|
94
97
|
const [selected, setSelected] = useState<DefaultMcpIntegration | null>(null);
|
|
95
|
-
const
|
|
98
|
+
const safeDefaultScope = resolveMcpIntegrationScope(
|
|
99
|
+
defaultScope,
|
|
100
|
+
hasOrg,
|
|
101
|
+
canCreateOrgMcp,
|
|
102
|
+
);
|
|
103
|
+
const [scope, setScope] = useState<McpServerScope>(safeDefaultScope);
|
|
96
104
|
const [name, setName] = useState("");
|
|
97
105
|
const [url, setUrl] = useState("");
|
|
98
106
|
const [description, setDescription] = useState("");
|
|
@@ -135,7 +143,7 @@ export function McpIntegrationDialog({
|
|
|
135
143
|
setMode(showCatalog ? "catalog" : "form");
|
|
136
144
|
setQuery("");
|
|
137
145
|
setSelected(null);
|
|
138
|
-
setScope(
|
|
146
|
+
setScope(safeDefaultScope);
|
|
139
147
|
setName("");
|
|
140
148
|
setUrl("");
|
|
141
149
|
setDescription("");
|
|
@@ -144,7 +152,7 @@ export function McpIntegrationDialog({
|
|
|
144
152
|
setQuickBusyId(null);
|
|
145
153
|
setError(null);
|
|
146
154
|
setTestResult(null);
|
|
147
|
-
}, [
|
|
155
|
+
}, [open, safeDefaultScope, showCatalog]);
|
|
148
156
|
|
|
149
157
|
useEffect(() => {
|
|
150
158
|
if (open && mode === "form") {
|
|
@@ -161,7 +169,7 @@ export function McpIntegrationDialog({
|
|
|
161
169
|
const openForm = (integration?: DefaultMcpIntegration | null) => {
|
|
162
170
|
const defaults = createMcpIntegrationFormDefaults(integration);
|
|
163
171
|
setSelected(integration ?? null);
|
|
164
|
-
setScope(
|
|
172
|
+
setScope(safeDefaultScope);
|
|
165
173
|
setName(defaults.name);
|
|
166
174
|
setUrl(defaults.url);
|
|
167
175
|
setDescription(defaults.description);
|
|
@@ -171,6 +179,55 @@ export function McpIntegrationDialog({
|
|
|
171
179
|
setMode("form");
|
|
172
180
|
};
|
|
173
181
|
|
|
182
|
+
const beginOAuth = (args: {
|
|
183
|
+
name: string;
|
|
184
|
+
url: string;
|
|
185
|
+
description: string;
|
|
186
|
+
}) => {
|
|
187
|
+
const validationError = getMcpUrlValidationError(args.url);
|
|
188
|
+
if (validationError) {
|
|
189
|
+
setError(validationError);
|
|
190
|
+
setTestResult(null);
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
const returnUrl =
|
|
194
|
+
typeof window === "undefined"
|
|
195
|
+
? "/"
|
|
196
|
+
: window.location.pathname +
|
|
197
|
+
window.location.search +
|
|
198
|
+
window.location.hash;
|
|
199
|
+
window.location.assign(
|
|
200
|
+
agentNativePath(
|
|
201
|
+
buildMcpOAuthStartUrl({
|
|
202
|
+
name: args.name,
|
|
203
|
+
url: args.url,
|
|
204
|
+
description: args.description,
|
|
205
|
+
scope: safeDefaultScope,
|
|
206
|
+
returnUrl,
|
|
207
|
+
}),
|
|
208
|
+
),
|
|
209
|
+
);
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
const connectWithOAuth = (integration: DefaultMcpIntegration) =>
|
|
213
|
+
beginOAuth({
|
|
214
|
+
name: integration.name,
|
|
215
|
+
url: integration.url,
|
|
216
|
+
description: integration.description,
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
const connectCustomWithOAuth = () => {
|
|
220
|
+
if (!name.trim()) {
|
|
221
|
+
setError(t("mcpIntegrations.serverNameRequired"));
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
beginOAuth({
|
|
225
|
+
name: name.trim(),
|
|
226
|
+
url: url.trim(),
|
|
227
|
+
description: description.trim(),
|
|
228
|
+
});
|
|
229
|
+
};
|
|
230
|
+
|
|
174
231
|
const createServer = async (
|
|
175
232
|
args: CreateMcpServerArgs,
|
|
176
233
|
options?: { quickId?: string },
|
|
@@ -211,13 +268,17 @@ export function McpIntegrationDialog({
|
|
|
211
268
|
};
|
|
212
269
|
|
|
213
270
|
const quickConnect = (integration: DefaultMcpIntegration) => {
|
|
214
|
-
if (integration.authMode
|
|
271
|
+
if (integration.authMode === "oauth") {
|
|
272
|
+
connectWithOAuth(integration);
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
if (integration.authMode === "headers") {
|
|
215
276
|
openForm(integration);
|
|
216
277
|
return;
|
|
217
278
|
}
|
|
218
279
|
void createServer(
|
|
219
280
|
{
|
|
220
|
-
scope:
|
|
281
|
+
scope: safeDefaultScope,
|
|
221
282
|
name: integration.name,
|
|
222
283
|
url: integration.url,
|
|
223
284
|
description: integration.description,
|
|
@@ -350,7 +411,7 @@ export function McpIntegrationDialog({
|
|
|
350
411
|
const connected = connectedUrls.has(
|
|
351
412
|
compareUrl(integration.url),
|
|
352
413
|
);
|
|
353
|
-
const
|
|
414
|
+
const requiresHeaders = integration.authMode === "headers";
|
|
354
415
|
return (
|
|
355
416
|
<article
|
|
356
417
|
key={integration.id}
|
|
@@ -381,9 +442,11 @@ export function McpIntegrationDialog({
|
|
|
381
442
|
) : null}
|
|
382
443
|
{connected
|
|
383
444
|
? t("mcpIntegrations.connected")
|
|
384
|
-
:
|
|
385
|
-
? t("mcpIntegrations.
|
|
386
|
-
:
|
|
445
|
+
: integration.authMode === "oauth"
|
|
446
|
+
? t("mcpIntegrations.connectWithOAuth")
|
|
447
|
+
: requiresHeaders
|
|
448
|
+
? t("mcpIntegrations.configure")
|
|
449
|
+
: t("mcpIntegrations.connect")}
|
|
387
450
|
</button>
|
|
388
451
|
{integration.docsUrl && (
|
|
389
452
|
<Tooltip>
|
|
@@ -507,28 +570,30 @@ export function McpIntegrationDialog({
|
|
|
507
570
|
placeholder={t("mcpIntegrations.descriptionPlaceholder")}
|
|
508
571
|
/>
|
|
509
572
|
</label>
|
|
510
|
-
|
|
511
|
-
<
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
573
|
+
{selected?.authMode !== "oauth" && (
|
|
574
|
+
<label className="block">
|
|
575
|
+
<span className="mb-1 block text-[10px] font-medium text-muted-foreground">
|
|
576
|
+
{t("mcpIntegrations.headers")}
|
|
577
|
+
</span>
|
|
578
|
+
<textarea
|
|
579
|
+
value={headersText}
|
|
580
|
+
onChange={(event) => {
|
|
581
|
+
setHeadersText(event.target.value);
|
|
582
|
+
clearFeedback();
|
|
583
|
+
}}
|
|
584
|
+
rows={3}
|
|
585
|
+
className="w-full resize-y rounded-md border border-border bg-background px-2.5 py-1.5 text-[12px] text-foreground outline-none placeholder:text-muted-foreground/50 focus:ring-1 focus:ring-ring"
|
|
586
|
+
style={{
|
|
587
|
+
fontFamily:
|
|
588
|
+
'ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace',
|
|
589
|
+
}}
|
|
590
|
+
placeholder={
|
|
591
|
+
selected?.headerPlaceholder ??
|
|
592
|
+
t("mcpIntegrations.headersPlaceholder")
|
|
593
|
+
}
|
|
594
|
+
/>
|
|
595
|
+
</label>
|
|
596
|
+
)}
|
|
532
597
|
{selected?.docsUrl && (
|
|
533
598
|
<a
|
|
534
599
|
href={selected.docsUrl}
|
|
@@ -573,6 +638,16 @@ export function McpIntegrationDialog({
|
|
|
573
638
|
>
|
|
574
639
|
{t("mcpIntegrations.test")}
|
|
575
640
|
</button>
|
|
641
|
+
{!selected && (
|
|
642
|
+
<button
|
|
643
|
+
type="button"
|
|
644
|
+
onClick={connectCustomWithOAuth}
|
|
645
|
+
disabled={!name.trim() || !url.trim() || busy}
|
|
646
|
+
className="rounded-md border border-border bg-background px-3 py-1.5 text-[12px] font-medium text-foreground hover:bg-accent disabled:pointer-events-none disabled:opacity-40"
|
|
647
|
+
>
|
|
648
|
+
{t("mcpIntegrations.connectWithOAuth")}
|
|
649
|
+
</button>
|
|
650
|
+
)}
|
|
576
651
|
<button
|
|
577
652
|
type="button"
|
|
578
653
|
onClick={submitForm}
|
|
@@ -33,6 +33,14 @@ export interface McpIntegrationFormDefaults {
|
|
|
33
33
|
headersText: string;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
export interface McpOAuthStartParams {
|
|
37
|
+
name: string;
|
|
38
|
+
url: string;
|
|
39
|
+
description: string;
|
|
40
|
+
scope: "user" | "org";
|
|
41
|
+
returnUrl: string;
|
|
42
|
+
}
|
|
43
|
+
|
|
36
44
|
export const DEFAULT_MCP_INTEGRATIONS: DefaultMcpIntegration[] = [
|
|
37
45
|
{
|
|
38
46
|
id: "context7",
|
|
@@ -215,6 +223,31 @@ export function mcpIntegrationAuthLabel(mode: McpIntegrationAuthMode): string {
|
|
|
215
223
|
return "OAuth";
|
|
216
224
|
}
|
|
217
225
|
|
|
226
|
+
export function buildMcpOAuthStartUrl({
|
|
227
|
+
name,
|
|
228
|
+
url,
|
|
229
|
+
description,
|
|
230
|
+
scope,
|
|
231
|
+
returnUrl,
|
|
232
|
+
}: McpOAuthStartParams): string {
|
|
233
|
+
const params = new URLSearchParams({
|
|
234
|
+
name,
|
|
235
|
+
url,
|
|
236
|
+
description,
|
|
237
|
+
scope,
|
|
238
|
+
return: returnUrl,
|
|
239
|
+
});
|
|
240
|
+
return `/_agent-native/mcp/servers/oauth/start?${params.toString()}`;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
export function resolveMcpIntegrationScope(
|
|
244
|
+
defaultScope: "user" | "org",
|
|
245
|
+
hasOrg: boolean,
|
|
246
|
+
canCreateOrgMcp: boolean,
|
|
247
|
+
): "user" | "org" {
|
|
248
|
+
return defaultScope === "org" && hasOrg && canCreateOrgMcp ? "org" : "user";
|
|
249
|
+
}
|
|
250
|
+
|
|
218
251
|
export function filterMcpIntegrations(
|
|
219
252
|
query: string,
|
|
220
253
|
integrations: DefaultMcpIntegration[] = getDefaultMcpIntegrations(),
|