@agent-native/core 0.148.1 → 0.149.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 +1 -1
- package/corpus/templates/analytics/changelog/2026-08-10-wide-tables-in-analytics-chat-now-scroll-horizontally-within.md +6 -0
- package/corpus/templates/calendar/app/components/calendar/DayView.tsx +13 -53
- package/corpus/templates/calendar/app/components/calendar/WeekView.tsx +11 -70
- package/corpus/templates/calendar/app/lib/event-layout.ts +122 -0
- package/corpus/templates/calendar/app/routes/_app.availability.tsx +1 -1
- package/corpus/templates/calendar/changelog/2026-08-10-opening-availability-settings-from-the-agent-lands-on-the-av.md +6 -0
- package/corpus/templates/calendar/vitest.config.ts +6 -1
- package/corpus/templates/clips/actions/lib/audio-only-transcription.ts +3 -1
- package/corpus/templates/clips/app/components/player/video-player.tsx +44 -4
- package/corpus/templates/clips/changelog/2026-08-10-fixed-transcription-failures-for-recordings-without-captured.md +6 -0
- package/corpus/templates/clips/changelog/2026-08-10-mobile-clips-can-now-enter-fullscreen-on-iphone-safari.md +6 -0
- package/corpus/templates/content/actions/_property-utils.ts +11 -1
- package/corpus/templates/content/actions/view-screen.ts +62 -12
- package/corpus/templates/content/server/plugins/agent-chat.ts +2 -0
- package/corpus/templates/design/.agents/skills/design-templates/SKILL.md +22 -0
- package/corpus/templates/design/AGENTS.md +3 -0
- package/corpus/templates/design/actions/create-design-from-template.ts +19 -0
- package/corpus/templates/design/actions/get-design-snapshot.ts +18 -0
- package/corpus/templates/design/actions/get-design-template.ts +178 -0
- package/corpus/templates/design/actions/list-designs.ts +3 -1
- package/corpus/templates/design/actions/view-screen.ts +31 -0
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +225 -214
- package/corpus/templates/design/app/components/design/multi-screen/types.ts +3 -0
- package/corpus/templates/design/app/i18n-data.ts +78 -0
- package/corpus/templates/design/app/lib/design-authors.ts +64 -0
- package/corpus/templates/design/app/pages/Index.tsx +114 -4
- package/corpus/templates/design/app/pages/design-editor/generation-prompt-directives.ts +1 -0
- package/corpus/templates/design/changelog/2026-08-07-alt-dragging-an-element-to-copy-it-now-keeps-the-copy-visibl.md +6 -0
- package/corpus/templates/design/changelog/2026-08-07-design-cards-now-show-who-created-each-design-with-a-filter-.md +6 -0
- package/corpus/templates/design/changelog/2026-08-07-drawing-a-shape-on-the-overview-canvas-now-keeps-the-shape-s.md +6 -0
- package/corpus/templates/design/changelog/2026-08-07-hold-option-alt-while-dragging-a-frame-on-the-overview-canva.md +6 -0
- package/corpus/templates/design/server/lib/design-template-data.ts +143 -0
- package/corpus/templates/design/server/plugins/agent-chat.ts +1 -0
- package/corpus/templates/forms/AGENTS.md +2 -2
- package/corpus/templates/forms/actions/create-form.ts +1 -1
- package/corpus/templates/forms/actions/update-form.ts +5 -5
- package/corpus/templates/forms/changelog/2026-08-10-forms-now-keep-agent-applied-field-changes-visible-after-an-.md +6 -0
- package/corpus/templates/forms/changelog/2026-08-10-published-form-links-always-use-the-working-public-form-url.md +6 -0
- package/corpus/templates/forms/server/plugins/agent-chat.ts +2 -2
- package/corpus/templates/slides/AGENTS.md +4 -3
- package/corpus/templates/slides/actions/import-google-slides-reference.ts +56 -10
- package/corpus/templates/slides/actions/patch-deck.ts +18 -2
- package/corpus/templates/slides/app/components/deck/SlideRenderer.tsx +46 -0
- package/corpus/templates/slides/app/components/editor/BlockBubbleMenu.tsx +194 -3
- package/corpus/templates/slides/app/components/editor/EditorSidebar.tsx +22 -75
- package/corpus/templates/slides/app/components/editor/ExportMenu.tsx +5 -3
- package/corpus/templates/slides/app/components/editor/GeneratingSlidePreview.tsx +5 -1
- package/corpus/templates/slides/app/components/editor/GoogleDriveConnectionCta.tsx +15 -4
- package/corpus/templates/slides/app/components/editor/NewDeckReferenceStep.tsx +116 -55
- package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +27 -4
- package/corpus/templates/slides/app/components/editor/slide-object-interactions.ts +45 -0
- package/corpus/templates/slides/app/components/onboarding/FirstDeckOnboardingFlow.tsx +143 -18
- package/corpus/templates/slides/app/i18n/en-US.ts +6 -0
- package/corpus/templates/slides/app/lib/export-pdf-client.ts +84 -25
- package/corpus/templates/slides/app/lib/generation-state.ts +7 -1
- package/corpus/templates/slides/app/lib/import-uploaded-deck.ts +11 -0
- package/corpus/templates/slides/app/pages/DeckEditor.tsx +44 -14
- package/corpus/templates/slides/app/pages/Index.tsx +124 -135
- package/corpus/templates/slides/changelog/2026-08-08-google-slides-export-now-tells-you-why-a-deck-fell-back-to-a.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-09-delete-key-now-removes-a-selected-image.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-09-editing-a-slide-in-an-imported-deck-no-longer-fails-to-save.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-09-fixed-pdf-and-custom-size-powerpoint-imports-rendering-with-.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-09-images-from-sites-without-cors-no-longer-export-blank.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-09-imported-pdf-headings-no-longer-lose-the-space-between-color.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-09-imported-slide-text-no-longer-renders-too-large-for-its-box.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-09-large-decks-no-longer-render-slowly-or-glitch-in-the-editor.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-09-revise-highlighted-slide-text-with-ai.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-09-the-deck-editor-no-longer-stays-dimmed-after-the-window-narro.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-10-imported-reference-decks-now-show-clear-success-and-stay-sel.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-10-pasted-google-slides-links-import-after-reconnecting-google-.md +6 -0
- package/corpus/templates/slides/server/handlers/google-docs-auth.ts +4 -0
- package/corpus/templates/slides/server/handlers/import/html-converter.ts +115 -22
- package/corpus/templates/slides/server/handlers/import/pdf-fidelity-parser.ts +11 -2
- package/corpus/templates/slides/server/lib/fetch-remote-image.ts +192 -0
- package/corpus/templates/slides/server/lib/google-docs-oauth.ts +13 -0
- package/corpus/templates/slides/server/lib/image-proxy-url.ts +192 -0
- package/corpus/templates/slides/server/plugins/agent-chat.ts +1 -1
- package/corpus/templates/slides/server/routes/api/image-proxy.get.ts +65 -0
- package/dist/agent/engine/registry.d.ts +8 -2
- package/dist/agent/engine/registry.js +63 -29
- package/dist/agent/production-agent.js +7 -0
- package/dist/agent/run-manager.d.ts +5 -4
- package/dist/agent/run-manager.js +6 -5
- package/dist/cli/claude-code-participant.d.ts +2 -1
- package/dist/cli/claude-code-participant.js +19 -0
- package/dist/cli/code-agent-executor.js +223 -0
- package/dist/cli/create-workspace.js +3 -3
- package/dist/cli/create.d.ts +3 -2
- package/dist/cli/create.js +20 -24
- package/dist/client/AgentPanel.js +8 -4
- package/dist/client/AssistantChat.js +34 -1
- package/dist/client/agent-chat-adapter.d.ts +1 -0
- package/dist/client/agent-chat-adapter.js +10 -2
- package/dist/client/chat/markdown-renderer.d.ts +1 -0
- package/dist/client/chat/markdown-renderer.js +4 -0
- package/dist/client/chat/message-components.d.ts +1 -0
- package/dist/client/chat/message-components.js +9 -1
- package/dist/client/chat/tool-call-display.d.ts +8 -0
- package/dist/client/chat/tool-call-display.js +30 -21
- package/dist/client/chat-first/app-pane.js +1 -1
- package/dist/client/chat-first/apps-rail.d.ts +1 -1
- package/dist/client/chat-first/apps-rail.js +11 -11
- package/dist/client/chat-first/chat-history.d.ts +1 -1
- package/dist/client/chat-first/chat-history.js +2 -0
- package/dist/client/chat-first/primary-nav.js +1 -1
- package/dist/client/progress/RunsTray.js +14 -1
- package/dist/client/resources/McpConnectionSuggestion.js +2 -2
- package/dist/client/settings/SettingsTabsPage.d.ts +3 -1
- package/dist/client/settings/SettingsTabsPage.js +2 -2
- package/dist/client/sse-event-processor.d.ts +8 -0
- package/dist/client/sse-event-processor.js +13 -6
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/routes.d.ts +1 -1
- package/dist/deploy/build.d.ts +5 -7
- package/dist/deploy/build.js +19 -12
- package/dist/localization/default-messages.js +1 -1
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/observability/routes.d.ts +6 -6
- package/dist/provider-api/actions/provider-api.d.ts +2 -2
- package/dist/scripts/call-agent.js +3 -3
- package/dist/scripts/describe-workspace-apps.js +1 -1
- package/dist/server/agent-capabilities.js +0 -0
- package/dist/server/agent-chat/context-tools.js +1 -1
- package/dist/server/agent-chat/prompt-resources.js +1 -1
- package/dist/server/agent-chat-plugin.js +1 -1
- package/dist/server/auth.js +190 -42
- package/dist/server/better-auth-migrations.js +53 -0
- package/dist/server/http-response-telemetry.js +7 -1
- package/dist/server/onboarding-html.js +119 -33
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/shared/password-policy.d.ts +2 -1
- package/dist/shared/password-policy.js +2 -1
- package/dist/styles/agent-conversation.css +20 -3
- package/dist/styles/agent-native.css +14 -2
- package/dist/templates/default/app/i18n/ar-SA.ts +1 -1
- package/dist/templates/default/app/i18n/de-DE.ts +1 -1
- package/dist/templates/default/app/i18n/en-US.ts +1 -1
- package/dist/templates/default/app/i18n/es-ES.ts +1 -1
- package/dist/templates/default/app/i18n/fr-FR.ts +1 -1
- package/dist/templates/default/app/i18n/hi-IN.ts +1 -1
- package/dist/templates/default/app/i18n/ja-JP.ts +1 -1
- package/dist/templates/default/app/i18n/ko-KR.ts +1 -1
- package/dist/templates/default/app/i18n/pt-BR.ts +1 -1
- package/dist/templates/default/app/i18n/zh-CN.ts +1 -1
- package/dist/templates/default/app/i18n/zh-TW.ts +1 -1
- package/dist/templates/default/pnpm-workspace.yaml +1 -0
- package/dist/templates/workspace-root/pnpm-workspace.yaml +2 -0
- package/docs/content/cloneable-saas.mdx +6 -6
- package/docs/content/deployment.mdx +10 -8
- package/docs/content/environment-variables.mdx +4 -3
- package/package.json +2 -2
- package/src/templates/default/app/i18n/ar-SA.ts +1 -1
- package/src/templates/default/app/i18n/de-DE.ts +1 -1
- package/src/templates/default/app/i18n/en-US.ts +1 -1
- package/src/templates/default/app/i18n/es-ES.ts +1 -1
- package/src/templates/default/app/i18n/fr-FR.ts +1 -1
- package/src/templates/default/app/i18n/hi-IN.ts +1 -1
- package/src/templates/default/app/i18n/ja-JP.ts +1 -1
- package/src/templates/default/app/i18n/ko-KR.ts +1 -1
- package/src/templates/default/app/i18n/pt-BR.ts +1 -1
- package/src/templates/default/app/i18n/zh-CN.ts +1 -1
- package/src/templates/default/app/i18n/zh-TW.ts +1 -1
- package/src/templates/default/pnpm-workspace.yaml +1 -0
- package/src/templates/workspace-root/pnpm-workspace.yaml +2 -0
|
@@ -14,6 +14,7 @@ import { readAgentsBundleFromFs, generateDevelopmentSkillsPromptBlock, } from ".
|
|
|
14
14
|
import { getAmbientOrgId, getAmbientUserEmail, runWithRequestContext, } from "../server/request-context.js";
|
|
15
15
|
import { isReasoningEffort, } from "../shared/reasoning-effort.js";
|
|
16
16
|
import { createAgentNativeConfigContext, loadResolvedAgentNativeConfig, } from "../vite/agent-native-config-loader.js";
|
|
17
|
+
import { runClaudeCodeParticipant, } from "./claude-code-participant.js";
|
|
17
18
|
import { codexMcpConfigArgs, mergeCodeAgentMcpConfig, restrictCodeAgentMcpConfig, } from "./code-agent-mcp-config.js";
|
|
18
19
|
import { createCodeAgentOutputSmoother } from "./code-agent-output-smoother.js";
|
|
19
20
|
import { addCodeAgentCommandToAllowlist, appendCodeAgentTranscriptEvent, dequeueCodeAgentFollowUp, getCodeAgentRunRecord, isCodeAgentCommandAllowed, listCodeAgentTranscriptEvents, updateCodeAgentRunRecord, } from "./code-agent-runs.js";
|
|
@@ -21,6 +22,8 @@ const DEFAULT_COMMAND_TIMEOUT_MS = 120_000;
|
|
|
21
22
|
const MAX_TOOL_OUTPUT_CHARS = 50_000;
|
|
22
23
|
const MAX_FILE_READ_CHARS = 120_000;
|
|
23
24
|
const CODEX_CLI_ENGINE_NAME = "codex-cli";
|
|
25
|
+
const CLAUDE_CLI_ENGINE_NAME = "claude-cli";
|
|
26
|
+
const CLAUDE_CLI_DEFAULT_MODEL = "claude-sonnet-5";
|
|
24
27
|
const RECAP_SOURCE_TOOL_PROFILE = "recap-source";
|
|
25
28
|
const RECAP_SOURCE_OUTPUT_FILE = "recap-source.json";
|
|
26
29
|
/**
|
|
@@ -110,6 +113,18 @@ export async function executeCodeAgentRun(options) {
|
|
|
110
113
|
signal: options.signal,
|
|
111
114
|
});
|
|
112
115
|
}
|
|
116
|
+
if (requestedEngine === CLAUDE_CLI_ENGINE_NAME) {
|
|
117
|
+
return executeClaudeCliRun({
|
|
118
|
+
run: existing,
|
|
119
|
+
prompt: executionPrompt,
|
|
120
|
+
model: options.model ?? metadataString(existing, "model"),
|
|
121
|
+
reasoningEffort: options.reasoningEffort ?? metadataReasoningEffort(existing),
|
|
122
|
+
permissionMode: existing.permissionMode ?? "full-auto",
|
|
123
|
+
stdout: options.stdout,
|
|
124
|
+
streamToolOutputToStdout,
|
|
125
|
+
signal: options.signal,
|
|
126
|
+
});
|
|
127
|
+
}
|
|
113
128
|
const engine = options.engine ?? (await resolveExecutorEngine(requestedEngine));
|
|
114
129
|
if (!engine) {
|
|
115
130
|
const message = "No LLM provider key was found. Set ANTHROPIC_API_KEY, OPENAI_API_KEY, GOOGLE_GENERATIVE_AI_API_KEY, another supported provider key, or run `codex login` to use Codex CLI.";
|
|
@@ -437,6 +452,214 @@ export function codeAgentMcpInvocationPolicy(permissionMode) {
|
|
|
437
452
|
mode: permissionMode === "read-only" ? "read-only" : "allow-all",
|
|
438
453
|
};
|
|
439
454
|
}
|
|
455
|
+
async function executeClaudeCliRun(options) {
|
|
456
|
+
const cwd = options.run.cwd || process.cwd();
|
|
457
|
+
const model = normalizeClaudeCliModel(options.model);
|
|
458
|
+
const reasoningEffort = normalizeClaudeCliEffort(options.reasoningEffort);
|
|
459
|
+
const streamToolOutputToStdout = options.streamToolOutputToStdout ??
|
|
460
|
+
process.env.AGENT_NATIVE_CODE_AGENT_STRUCTURED_STDOUT !== "1";
|
|
461
|
+
const assistantText = [];
|
|
462
|
+
appendCodeAgentTranscriptEvent({
|
|
463
|
+
runId: options.run.id,
|
|
464
|
+
kind: "status",
|
|
465
|
+
message: "Starting Claude Code with local Claude authentication.",
|
|
466
|
+
metadata: {
|
|
467
|
+
status: "running",
|
|
468
|
+
phase: "executing",
|
|
469
|
+
engine: CLAUDE_CLI_ENGINE_NAME,
|
|
470
|
+
},
|
|
471
|
+
});
|
|
472
|
+
try {
|
|
473
|
+
const result = await runClaudeCodeParticipant({
|
|
474
|
+
role: options.permissionMode === "full-auto" ? "driver" : "watchdog",
|
|
475
|
+
prompt: buildClaudeCliPrompt(options.run, options.prompt),
|
|
476
|
+
cwd,
|
|
477
|
+
model,
|
|
478
|
+
effort: reasoningEffort,
|
|
479
|
+
signal: options.signal,
|
|
480
|
+
onEvent: (event) => {
|
|
481
|
+
const text = readClaudeParticipantAssistantText(event);
|
|
482
|
+
if (!text)
|
|
483
|
+
return;
|
|
484
|
+
assistantText.push(text);
|
|
485
|
+
if (streamToolOutputToStdout)
|
|
486
|
+
options.stdout?.write(text);
|
|
487
|
+
},
|
|
488
|
+
});
|
|
489
|
+
const finalMessage = readClaudeParticipantResultText(result.events) ??
|
|
490
|
+
(assistantText.join("\n\n").trim() || "Claude Code run completed.");
|
|
491
|
+
appendCodeAgentTranscriptEvent({
|
|
492
|
+
runId: options.run.id,
|
|
493
|
+
kind: "system",
|
|
494
|
+
message: finalMessage,
|
|
495
|
+
metadata: {
|
|
496
|
+
role: "assistant",
|
|
497
|
+
engine: CLAUDE_CLI_ENGINE_NAME,
|
|
498
|
+
model,
|
|
499
|
+
...(reasoningEffort ? { reasoningEffort } : {}),
|
|
500
|
+
},
|
|
501
|
+
});
|
|
502
|
+
const pendingFollowUp = dequeueCodeAgentFollowUp(options.run.id);
|
|
503
|
+
if (pendingFollowUp) {
|
|
504
|
+
const message = pendingFollowUp.mode === "queued"
|
|
505
|
+
? "Claude Code run completed; running queued follow-up."
|
|
506
|
+
: "Claude Code run completed; applying steering follow-up.";
|
|
507
|
+
appendCodeAgentTranscriptEvent({
|
|
508
|
+
runId: options.run.id,
|
|
509
|
+
kind: "status",
|
|
510
|
+
message,
|
|
511
|
+
metadata: {
|
|
512
|
+
status: "running",
|
|
513
|
+
phase: "follow-up",
|
|
514
|
+
followUpId: pendingFollowUp.id,
|
|
515
|
+
followUpMode: pendingFollowUp.mode,
|
|
516
|
+
engine: CLAUDE_CLI_ENGINE_NAME,
|
|
517
|
+
},
|
|
518
|
+
});
|
|
519
|
+
if (pendingFollowUp.permissionMode) {
|
|
520
|
+
updateCodeAgentRunRecord(options.run.id, {
|
|
521
|
+
permissionMode: pendingFollowUp.permissionMode,
|
|
522
|
+
});
|
|
523
|
+
}
|
|
524
|
+
return executeCodeAgentRun({
|
|
525
|
+
runId: options.run.id,
|
|
526
|
+
prompt: pendingFollowUp.prompt,
|
|
527
|
+
attachments: pendingFollowUp.attachments ??
|
|
528
|
+
userPromptAttachmentsForEvent(options.run.id, pendingFollowUp.eventId),
|
|
529
|
+
appendUserEvent: false,
|
|
530
|
+
stdout: options.stdout,
|
|
531
|
+
streamToolOutputToStdout: options.streamToolOutputToStdout,
|
|
532
|
+
signal: options.signal,
|
|
533
|
+
});
|
|
534
|
+
}
|
|
535
|
+
appendCodeAgentTranscriptEvent({
|
|
536
|
+
runId: options.run.id,
|
|
537
|
+
kind: "status",
|
|
538
|
+
message: "Claude Code run completed.",
|
|
539
|
+
metadata: {
|
|
540
|
+
status: "completed",
|
|
541
|
+
phase: "complete",
|
|
542
|
+
engine: CLAUDE_CLI_ENGINE_NAME,
|
|
543
|
+
},
|
|
544
|
+
});
|
|
545
|
+
return updateCodeAgentRunRecord(options.run.id, {
|
|
546
|
+
status: "completed",
|
|
547
|
+
phase: "complete",
|
|
548
|
+
needsApproval: false,
|
|
549
|
+
progress: {
|
|
550
|
+
label: "Complete",
|
|
551
|
+
completed: 1,
|
|
552
|
+
total: 1,
|
|
553
|
+
percent: 100,
|
|
554
|
+
},
|
|
555
|
+
metadata: {
|
|
556
|
+
executionCompletedAt: new Date().toISOString(),
|
|
557
|
+
engine: CLAUDE_CLI_ENGINE_NAME,
|
|
558
|
+
model,
|
|
559
|
+
...(reasoningEffort ? { reasoningEffort } : {}),
|
|
560
|
+
permissionMode: options.permissionMode,
|
|
561
|
+
},
|
|
562
|
+
});
|
|
563
|
+
}
|
|
564
|
+
catch (error) {
|
|
565
|
+
const interrupted = options.signal?.aborted === true;
|
|
566
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
567
|
+
const summary = interrupted
|
|
568
|
+
? "Claude Code run paused."
|
|
569
|
+
: `Claude Code run failed: ${message}`;
|
|
570
|
+
if (streamToolOutputToStdout)
|
|
571
|
+
options.stdout?.write(`\n${summary}\n`);
|
|
572
|
+
appendCodeAgentTranscriptEvent({
|
|
573
|
+
runId: options.run.id,
|
|
574
|
+
kind: "status",
|
|
575
|
+
message: summary,
|
|
576
|
+
metadata: {
|
|
577
|
+
status: interrupted ? "paused" : "errored",
|
|
578
|
+
phase: interrupted ? "paused" : "error",
|
|
579
|
+
engine: CLAUDE_CLI_ENGINE_NAME,
|
|
580
|
+
},
|
|
581
|
+
});
|
|
582
|
+
return updateCodeAgentRunRecord(options.run.id, {
|
|
583
|
+
status: interrupted ? "paused" : "errored",
|
|
584
|
+
phase: interrupted ? "paused" : "error",
|
|
585
|
+
progress: {
|
|
586
|
+
label: interrupted ? "Paused" : "Error",
|
|
587
|
+
completed: 0,
|
|
588
|
+
total: 1,
|
|
589
|
+
failed: interrupted ? 0 : 1,
|
|
590
|
+
percent: 0,
|
|
591
|
+
},
|
|
592
|
+
metadata: {
|
|
593
|
+
...(interrupted
|
|
594
|
+
? { executionPausedAt: new Date().toISOString() }
|
|
595
|
+
: {
|
|
596
|
+
executionError: message,
|
|
597
|
+
executionErroredAt: new Date().toISOString(),
|
|
598
|
+
}),
|
|
599
|
+
engine: CLAUDE_CLI_ENGINE_NAME,
|
|
600
|
+
model,
|
|
601
|
+
},
|
|
602
|
+
});
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
function buildClaudeCliPrompt(run, prompt) {
|
|
606
|
+
const permissionMode = run.permissionMode ?? "full-auto";
|
|
607
|
+
const mode = permissionMode === "full-auto" ? "Auto" : "Plan";
|
|
608
|
+
const modeInstruction = mode === "Plan"
|
|
609
|
+
? "Inspect and explain only. Do not edit files or run mutating commands."
|
|
610
|
+
: "Edit and verify as needed. Do not create, switch, reset, rebase, or stash git branches.";
|
|
611
|
+
const additionalSkillsRoot = process.env.AGENT_NATIVE_CODE_AGENT_SKILLS_ROOT?.trim();
|
|
612
|
+
return [
|
|
613
|
+
`You are running from Agent-Native Code in ${run.cwd || process.cwd()}.`,
|
|
614
|
+
"Follow the repository AGENTS.md and any relevant skill instructions.",
|
|
615
|
+
...(additionalSkillsRoot
|
|
616
|
+
? [
|
|
617
|
+
`Additional installed Agent Plugin skills are available under ${additionalSkillsRoot}. Read any relevant SKILL.md files before acting.`,
|
|
618
|
+
]
|
|
619
|
+
: []),
|
|
620
|
+
`Run mode: ${mode} (${permissionMode}). ${modeInstruction}`,
|
|
621
|
+
"",
|
|
622
|
+
"# User request",
|
|
623
|
+
prompt,
|
|
624
|
+
].join("\n");
|
|
625
|
+
}
|
|
626
|
+
function normalizeClaudeCliModel(model) {
|
|
627
|
+
const trimmed = model?.trim();
|
|
628
|
+
return !trimmed || trimmed === "auto" || trimmed === CLAUDE_CLI_ENGINE_NAME
|
|
629
|
+
? CLAUDE_CLI_DEFAULT_MODEL
|
|
630
|
+
: trimmed;
|
|
631
|
+
}
|
|
632
|
+
function normalizeClaudeCliEffort(effort) {
|
|
633
|
+
return effort && effort !== "auto" ? effort : undefined;
|
|
634
|
+
}
|
|
635
|
+
function readClaudeParticipantAssistantText(event) {
|
|
636
|
+
if (event.type !== "assistant")
|
|
637
|
+
return null;
|
|
638
|
+
const message = asRecordValue(event.message);
|
|
639
|
+
const content = message?.content;
|
|
640
|
+
if (!Array.isArray(content))
|
|
641
|
+
return null;
|
|
642
|
+
const text = content
|
|
643
|
+
.filter((part) => isRecordValue(part))
|
|
644
|
+
.map((part) => (typeof part.text === "string" ? part.text : ""))
|
|
645
|
+
.filter(Boolean)
|
|
646
|
+
.join("");
|
|
647
|
+
return text.trim() || null;
|
|
648
|
+
}
|
|
649
|
+
function readClaudeParticipantResultText(events) {
|
|
650
|
+
for (let index = events.length - 1; index >= 0; index -= 1) {
|
|
651
|
+
const result = events[index]?.result;
|
|
652
|
+
if (typeof result === "string" && result.trim())
|
|
653
|
+
return result.trim();
|
|
654
|
+
}
|
|
655
|
+
return null;
|
|
656
|
+
}
|
|
657
|
+
function isRecordValue(value) {
|
|
658
|
+
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
659
|
+
}
|
|
660
|
+
function asRecordValue(value) {
|
|
661
|
+
return isRecordValue(value) ? value : null;
|
|
662
|
+
}
|
|
440
663
|
async function executeCodexCliRun(options) {
|
|
441
664
|
const cwd = options.run.cwd || process.cwd();
|
|
442
665
|
const outputDir = fs.mkdtempSync(path.join(os.tmpdir(), "agent-native-code-codex-"));
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @deprecated `create-workspace` is now an alias for `create`. In current
|
|
3
|
-
* versions, `agent-native create <name>`
|
|
4
|
-
*
|
|
5
|
-
* standalone scaffold.
|
|
3
|
+
* versions, `agent-native create <name>` asks for a starting shape and its
|
|
4
|
+
* Chat/first-party template paths scaffold a workspace. Use `--standalone`
|
|
5
|
+
* for a single-app standalone scaffold.
|
|
6
6
|
*
|
|
7
7
|
* This module is kept for backwards compatibility with older docs and
|
|
8
8
|
* scripts that still invoke `agent-native create-workspace`.
|
package/dist/cli/create.d.ts
CHANGED
|
@@ -32,8 +32,9 @@ export interface CreateAppOptions {
|
|
|
32
32
|
/**
|
|
33
33
|
* Main entry for `agent-native create [name]`.
|
|
34
34
|
*
|
|
35
|
-
* Default behavior:
|
|
36
|
-
*
|
|
35
|
+
* Default behavior: ask for a starting shape, with Chat and first-party
|
|
36
|
+
* templates creating a workspace at <name>/. Use --standalone for the
|
|
37
|
+
* single-app standalone flow.
|
|
37
38
|
*
|
|
38
39
|
* If run *inside* an existing workspace, falls through to the add-app
|
|
39
40
|
* flow that scaffolds one new app under apps/<name>/.
|
package/dist/cli/create.js
CHANGED
|
@@ -93,8 +93,9 @@ const COMMUNITY_OPTION = {
|
|
|
93
93
|
/**
|
|
94
94
|
* Main entry for `agent-native create [name]`.
|
|
95
95
|
*
|
|
96
|
-
* Default behavior:
|
|
97
|
-
*
|
|
96
|
+
* Default behavior: ask for a starting shape, with Chat and first-party
|
|
97
|
+
* templates creating a workspace at <name>/. Use --standalone for the
|
|
98
|
+
* single-app standalone flow.
|
|
98
99
|
*
|
|
99
100
|
* If run *inside* an existing workspace, falls through to the add-app
|
|
100
101
|
* flow that scaffolds one new app under apps/<name>/.
|
|
@@ -126,8 +127,8 @@ export async function createApp(name, opts) {
|
|
|
126
127
|
}
|
|
127
128
|
// When exactly one template is specified explicitly, treat it as a
|
|
128
129
|
// standalone scaffold (script-friendly, matches historic behavior).
|
|
129
|
-
// Use `--template a,b`
|
|
130
|
-
//
|
|
130
|
+
// Use `--template a,b` to opt into the workspace flow with the multi-select
|
|
131
|
+
// picker. Bare `create` asks for the starting shape first.
|
|
131
132
|
const parsed = parseTemplateList(opts?.template);
|
|
132
133
|
// Headless can't live in a workspace, so reject it when more than one
|
|
133
134
|
// template is requested or when workspace semantics are forced.
|
|
@@ -146,9 +147,8 @@ export async function createApp(name, opts) {
|
|
|
146
147
|
// No template specified: ask what shape to start from before diving into
|
|
147
148
|
// "which templates?". The on-ramp choice implies the project structure, so
|
|
148
149
|
// we don't ask a separate "workspace or standalone?" question — Chat and
|
|
149
|
-
//
|
|
150
|
-
//
|
|
151
|
-
// multi-select.
|
|
150
|
+
// Template creates a workspace, while Community and Headless scaffold a
|
|
151
|
+
// single standalone app.
|
|
152
152
|
if (parsed.length === 0) {
|
|
153
153
|
// The deprecated `create-workspace` alias forces workspace semantics, so
|
|
154
154
|
// it must skip the start-shape prompt and scaffold a workspace directly.
|
|
@@ -157,10 +157,17 @@ export async function createApp(name, opts) {
|
|
|
157
157
|
return;
|
|
158
158
|
}
|
|
159
159
|
const shape = await promptStartShape(clack);
|
|
160
|
-
if (shape === "headless"
|
|
160
|
+
if (shape === "headless") {
|
|
161
161
|
await createStandaloneApp(name, { ...opts, template: shape }, clack);
|
|
162
162
|
return;
|
|
163
163
|
}
|
|
164
|
+
if (shape === "chat") {
|
|
165
|
+
// Chat is the default workspace on-ramp. Keep the minimal chat app in
|
|
166
|
+
// the same workspace shape as every other first-party app so the next
|
|
167
|
+
// documented step, `add-app`, works immediately.
|
|
168
|
+
await createWorkspaceInteractive(name, { ...opts, template: shape }, clack);
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
164
171
|
if (shape === "community") {
|
|
165
172
|
const template = await promptCommunityTemplate(clack);
|
|
166
173
|
await createStandaloneApp(name, { ...opts, template }, clack);
|
|
@@ -178,12 +185,11 @@ export async function createApp(name, opts) {
|
|
|
178
185
|
* choice made here implies the project structure, so we deliberately avoid a
|
|
179
186
|
* separate "workspace or standalone?" question:
|
|
180
187
|
* - "template" → full app(s) in a workspace (the multi-select picker)
|
|
188
|
+
* - "chat" → a minimal Chat app in a workspace with Dispatch
|
|
181
189
|
* - "community" → a single standalone app from a public GitHub repository
|
|
182
|
-
* - "chat" → a single standalone chat UI app
|
|
183
190
|
* - "headless" → a single standalone action-first app with no UI shell
|
|
184
|
-
*
|
|
185
|
-
*
|
|
186
|
-
* member. Either can grow into a workspace later via `add-app`.
|
|
191
|
+
* Headless cannot be a workspace member. Use `--standalone --template chat`
|
|
192
|
+
* when a standalone Chat app is the intended shape.
|
|
187
193
|
*/
|
|
188
194
|
async function promptStartShape(clack) {
|
|
189
195
|
const choice = await clack.select(startShapePromptOptions());
|
|
@@ -201,7 +207,7 @@ function startShapePromptOptions() {
|
|
|
201
207
|
{
|
|
202
208
|
value: "chat",
|
|
203
209
|
label: "Chat",
|
|
204
|
-
hint: "A
|
|
210
|
+
hint: "A minimal chat app in a workspace with the browser shell wired up",
|
|
205
211
|
},
|
|
206
212
|
{
|
|
207
213
|
value: "template",
|
|
@@ -1420,20 +1426,9 @@ function postProcessStandalone(name, targetDir, templateName, resolution) {
|
|
|
1420
1426
|
}
|
|
1421
1427
|
}
|
|
1422
1428
|
}
|
|
1423
|
-
// Ensure pnpm.onlyBuiltDependencies is set so native packages
|
|
1424
|
-
// (better-sqlite3, esbuild, node-pty) compile their postinstall scripts
|
|
1425
|
-
// under pnpm 10+ without prompting for `pnpm approve-builds`.
|
|
1426
1429
|
pkg.dependencies = pkg.dependencies ?? {};
|
|
1427
1430
|
pkg.dependencies.postgres ??= POSTGRES_DEPENDENCY_VERSION;
|
|
1428
1431
|
ensureReactRouterBuildDependencies(pkg);
|
|
1429
|
-
const requiredBuilt = ["better-sqlite3", "esbuild", "node-pty"];
|
|
1430
|
-
if (!pkg.pnpm || typeof pkg.pnpm !== "object") {
|
|
1431
|
-
pkg.pnpm = {};
|
|
1432
|
-
}
|
|
1433
|
-
const existing = Array.isArray(pkg.pnpm.onlyBuiltDependencies)
|
|
1434
|
-
? pkg.pnpm.onlyBuiltDependencies
|
|
1435
|
-
: [];
|
|
1436
|
-
pkg.pnpm.onlyBuiltDependencies = Array.from(new Set([...existing, ...requiredBuilt]));
|
|
1437
1432
|
fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
|
|
1438
1433
|
}
|
|
1439
1434
|
catch { }
|
|
@@ -1452,6 +1447,7 @@ function postProcessStandalone(name, targetDir, templateName, resolution) {
|
|
|
1452
1447
|
"better-sqlite3": "true",
|
|
1453
1448
|
esbuild: "true",
|
|
1454
1449
|
"node-pty": "true",
|
|
1450
|
+
"tesseract.js": "true",
|
|
1455
1451
|
},
|
|
1456
1452
|
};
|
|
1457
1453
|
if (templateName !== "headless") {
|
|
@@ -689,7 +689,11 @@ function AgentPanelInner({ defaultMode = "chat", className, style, apiUrl, empty
|
|
|
689
689
|
return (_jsx(ShareButton, { resourceType: "chat_thread", resourceId: activeTab.id, resourceTitle: activeTab.label || "Chat", shareUrl: getChatThreadShareUrl(activeTab.id), trigger: "icon", triggerClassName: "h-7 w-7" }));
|
|
690
690
|
})(), feedbackEnabled ? (_jsx(FeedbackButton, { variant: "icon", side: "bottom", align: "end", chatSessionId: activeChatSessionId, chatStorageKey: storageKey, open: feedbackOpen, onOpenChange: setFeedbackOpen, trigger: _jsx("button", { type: "button", tabIndex: -1, "aria-hidden": "true", className: "pointer-events-none absolute end-0 top-full h-px w-px opacity-0" }) })) : null, mode === "chat" && (_jsx(IconTooltip, { content: t("agentPanel.newChat"), children: _jsx("button", { onClick: addTab, "aria-label": t("agentPanel.newChat"), className: "flex h-6 w-6 items-center justify-center rounded text-muted-foreground hover:text-foreground hover:bg-accent/50", children: _jsx(IconPlus, { size: 14 }) }) })), !onCollapse && mode === "cli" && canUseCodeTools && (_jsx(IconTooltip, { content: t("agentPanel.newTerminal"), children: _jsx("button", { onClick: addCliTab, "aria-label": t("agentPanel.newTerminal"), className: "flex h-6 w-6 items-center justify-center rounded text-muted-foreground hover:text-foreground hover:bg-accent/50", children: _jsx(IconPlus, { size: 14 }) }) })), _jsxs(DropdownMenu, { open: headerMenuOpen, onOpenChange: setHeaderMenuOpen, children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx("button", { className: cn("flex h-6 w-6 items-center justify-center rounded text-muted-foreground hover:text-foreground hover:bg-accent/50", (headerMenuOpen || mode === "settings") &&
|
|
691
691
|
"bg-accent text-foreground"), "aria-label": t("agentPanel.panelOptions"), children: _jsx(IconDotsVertical, { size: 14 }) }) }), _jsxs(DropdownMenuContent, { align: "end", sideOffset: 6, className: "w-48", children: [onCollapse && (_jsxs(_Fragment, { children: [_jsxs(DropdownMenuItem, { onSelect: onCollapse, children: [_jsx(IconLayoutSidebarRightCollapse, { size: 14, className: "shrink-0" }), t("agentPanel.collapseSidebar"), _jsx(DropdownMenuShortcut, { children: toggleSidebarHint })] }), _jsx(DropdownMenuSeparator, {})] })), onCollapse && mode === "chat" && wideDrawerAction ? (_jsxs(DropdownMenuItem, { onSelect: wideDrawerAction, children: [_jsx(IconArrowsHorizontal, { size: 14, className: "shrink-0" }), wideDrawerLabel, _jsx(DropdownMenuShortcut, { children: widenChatHint })] })) : null, showFullViewAction && agentPageHref ? (_jsx(DropdownMenuItem, { asChild: true, children: _jsxs(Link, { to: agentPageHref, "aria-label": t("agentPanel.openFullView"), children: [_jsx(IconArrowsMaximize, { size: 14, className: "shrink-0" }), t("agentPanel.openFullView")] }) })) : null, (onCollapse && mode === "chat" && wideDrawerAction) ||
|
|
692
|
-
showFullViewAction ? (_jsx(DropdownMenuSeparator, {})) : null, onCollapse && mode === "chat" && (_jsxs(DropdownMenuItem, { onSelect: addTab, children: [_jsx(IconPlus, { size: 14, className: "shrink-0" }), t("agentPanel.newChat")] })), mode === "chat" && toggleHistory && (_jsxs(DropdownMenuItem, { onSelect:
|
|
692
|
+
showFullViewAction ? (_jsx(DropdownMenuSeparator, {})) : null, onCollapse && mode === "chat" && (_jsxs(DropdownMenuItem, { onSelect: addTab, children: [_jsx(IconPlus, { size: 14, className: "shrink-0" }), t("agentPanel.newChat")] })), mode === "chat" && toggleHistory && (_jsxs(DropdownMenuItem, { onSelect: () => {
|
|
693
|
+
// Let the menu finish restoring focus before mounting the
|
|
694
|
+
// history popover; otherwise Radix dismisses the new overlay.
|
|
695
|
+
setTimeout(() => toggleHistory(), 0);
|
|
696
|
+
}, children: [_jsx(IconHistory, { size: 14, className: "shrink-0" }), showHistory
|
|
693
697
|
? t("agentPanel.hideChats")
|
|
694
698
|
: t("agentPanel.allChats")] })), mode === "chat" && (_jsx(RunsTrayMenuItem, { pollMs: 0, limit: 12, showRecent: true, onOpenThread: openRunThread })), mode === "chat" && _jsx(DropdownMenuSeparator, {}), mode === "cli" && availableClis.length > 0 && (_jsxs(_Fragment, { children: [availableClis.map((cli) => (_jsxs(DropdownMenuItem, { onSelect: () => selectCli(cli.command), className: cn(cli.command === selectedCli
|
|
695
699
|
? "font-medium"
|
|
@@ -942,7 +946,7 @@ const SIDEBAR_OVERLAY_Z_INDEX = 70;
|
|
|
942
946
|
const SIDEBAR_DRAWER_Z_INDEX = 80;
|
|
943
947
|
const SIDEBAR_DRAWER_VIEW_TRANSITION_NAME = "agent-native-sidebar-drawer";
|
|
944
948
|
/** Shared max width of the centered fullscreen chat column and composer. */
|
|
945
|
-
const FULLSCREEN_CHAT_COLUMN_MAX_PX =
|
|
949
|
+
const FULLSCREEN_CHAT_COLUMN_MAX_PX = 750;
|
|
946
950
|
export function getActiveTabScrollDelta(containerRect, tabRect, margin = 24) {
|
|
947
951
|
if (tabRect.left < containerRect.left + margin) {
|
|
948
952
|
return tabRect.left - containerRect.left - margin;
|
|
@@ -1842,7 +1846,7 @@ export function AgentSidebar({ children, emptyStateText = "How can I help you?",
|
|
|
1842
1846
|
}
|
|
1843
1847
|
// Mount the live chat surface only while visible or actively needed. Keeping
|
|
1844
1848
|
// it mounted while closed starts app-state polling on every public page view.
|
|
1845
|
-
const sidebar = shouldRenderPanel ? (_jsxs(_Fragment, { children: [showResizeHandle && !isLeft && (_jsx(ResizeHandle, { position: position, onDrag: handleDrag, onResizeStart: handleResizeStart, onResizeEnd: handleResizeEnd })), _jsx("div", { className: cn("agent-sidebar-panel flex shrink-0 flex-col overflow-hidden text-[13px] leading-[1.2] antialiased", chatViewTransition && AGENT_CHAT_VIEW_TRANSITION_CLASS
|
|
1849
|
+
const sidebar = shouldRenderPanel ? (_jsxs(_Fragment, { children: [showResizeHandle && !isLeft && (_jsx(ResizeHandle, { position: position, onDrag: handleDrag, onResizeStart: handleResizeStart, onResizeEnd: handleResizeEnd })), _jsx("div", { className: cn("agent-sidebar-panel flex shrink-0 flex-col overflow-hidden text-[13px] leading-[1.2] antialiased", chatViewTransition && AGENT_CHAT_VIEW_TRANSITION_CLASS), "data-agent-sidebar-animation": wideDrawerEnabled
|
|
1846
1850
|
? "drawer"
|
|
1847
1851
|
: mobileAnimationEnabled
|
|
1848
1852
|
? "mobile"
|
|
@@ -1851,7 +1855,7 @@ export function AgentSidebar({ children, emptyStateText = "How can I help you?",
|
|
|
1851
1855
|
: undefined, "data-agent-sidebar-layout": panelLayout, "data-agent-sidebar-position": position, "data-agent-sidebar-state": panelOpen ? "open" : "closed", "data-agent-sidebar-resizing": isResizing ? "true" : undefined, "data-agent-sidebar-chat-handoff": chatViewTransitionHandoff ? "true" : undefined, style: chatViewTransition
|
|
1852
1856
|
? getAgentChatViewTransitionStyle(panelStyle)
|
|
1853
1857
|
: panelStyle, inert: sidebarAnimationEnabled && !panelOpen ? true : undefined, "aria-hidden": sidebarAnimationEnabled && !panelOpen ? true : undefined, children: _jsx("div", { className: "agent-sidebar-panel-inner flex min-h-0 flex-1 flex-col", children: _jsx(AgentPanel, { emptyStateText: emptyStateText, suggestions: suggestions, dynamicSuggestions: dynamicSuggestions, composerToolbarSlot: composerToolbarSlot, composerSlot: composerSlot, onComposerTextChange: onComposerTextChange, imageModelMenu: imageModelMenu, threadFooterSlot: threadFooterSlot, missingApiKeySetupLayout: "sidebar", onCollapse: () => setOpenPersisted(false), onSnapTo75Percent: isMobile ? undefined : snapTo75Percent, isWideDrawer: isMobile ? false : isWideDrawer, onExitWideDrawer: isMobile ? undefined : exitWideDrawer, storageKey: storageKey, scope: scope, showScopeBadge: showScopeBadge, browserTabId: browserTabId, threadUrlSync: threadUrlSync, agentPageHref: agentPageHref, allowSettingsMode: false, chatOnly: true }) }) }), showResizeHandle && isLeft && (_jsx(ResizeHandle, { position: position, onDrag: handleDrag, onResizeStart: handleResizeStart, onResizeEnd: handleResizeEnd }))] })) : null;
|
|
1854
|
-
const drawerPlaceholder = wideDrawerEnabled && !presentationMode &&
|
|
1858
|
+
const drawerPlaceholder = wideDrawerEnabled && !presentationMode && panelOpen ? (_jsx("div", { "aria-hidden": "true", className: "agent-sidebar-drawer-placeholder shrink-0", "data-agent-sidebar-placeholder": "true", style: { width: drawerPlaceholderWidth + 1 } })) : null;
|
|
1855
1859
|
return (_jsx(AgentSidebarOnboardingContext.Provider, { value: true, children: _jsxs(RealtimeVoiceModeProvider, { browserTabId: browserTabId, children: [showFirstRunOnboarding && (_jsx(Suspense, { fallback: null, children: _jsx(FirstRunOnboarding, {}) })), _jsxs("div", { className: "agent-sidebar-shell flex min-w-0 flex-1 h-screen overflow-hidden", "data-agent-sidebar-position": position, "data-agent-sidebar-resizing": isResizing ? "true" : undefined, children: [isMobile &&
|
|
1856
1860
|
!presentationMode &&
|
|
1857
1861
|
(mobileAnimationEnabled ? shouldRenderPanel : open) && (_jsx("div", { className: cn("agent-sidebar-backdrop fixed inset-0 bg-foreground/40", mobileAnimationEnabled && !panelOpen && "pointer-events-none"), "data-agent-sidebar-animation": mobileAnimationEnabled ? "mobile" : undefined, "data-agent-sidebar-state": panelOpen ? "open" : "closed", style: { zIndex: SIDEBAR_OVERLAY_Z_INDEX - 1 }, onClick: () => setOpenPersisted(false) })), shouldMountPanel ? _jsx(URLSync, { browserTabId: browserTabId }) : null, isLeft && !presentationMode ? sidebar : null, isLeft && !presentationMode ? drawerPlaceholder : null, _jsx("div", { className: "agent-sidebar-main-surface flex flex-1 flex-col overflow-auto min-w-0", "data-agent-sidebar-main-position": position, "data-agent-sidebar-main-state": !isMobile && !presentationMode && panelOpen ? "open" : "closed", "data-agent-sidebar-resizing": isResizing ? "true" : undefined, children: _jsx(ScreenRefreshBoundary, { children: children }) }), !isLeft && !presentationMode ? drawerPlaceholder : null, !isLeft && !presentationMode ? sidebar : null] })] }) }));
|
|
@@ -1346,6 +1346,9 @@ export function useAutoResumeStatus(tabId, forceStopped) {
|
|
|
1346
1346
|
}, [clearAutoResume, forceStopped]);
|
|
1347
1347
|
return { isAutoResuming, clearAutoResume };
|
|
1348
1348
|
}
|
|
1349
|
+
function approvalResolutionIdentity(approvalKey, toolCallId) {
|
|
1350
|
+
return `${toolCallId ?? ""}\u0000${approvalKey}`;
|
|
1351
|
+
}
|
|
1349
1352
|
const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateText, suggestions, dynamicSuggestions, threadFooterSlot, emptyStateAddon, showHeader = true, onSwitchToCli, className, apiUrl, tabId, browserTabId, threadId, contextScope, isActiveComposer = true, onMessageCountChange, onSaveThread, onGenerateTitle, composerSlot, onComposerTextChange, composerAreaClassName, composerPlaceholder, missingApiKeySetupLayout = "default", composerLayoutVariant = "default", centerComposerWhenEmpty = false, emptyStateDisplay = "default", composerToolbarSlot, composerExtraActionButton, composerDisabled = false, composerDisabledPlaceholder, isNewThread, isThreadStateLoading, onSlashCommand, execMode, onExecModeChange, approvalActions, planModeDisabled, planModeDisabledReason, selectedModel, defaultModel, selectedEngine, selectedEffort, availableModels, modelListLoading, onModelChange, onEffortChange, imageModelMenu, onForkChat, onConnectProvider, onConnectLocalRuntime, plusMenuMode = "full", providerStatusChecksEnabled = true, loadHistoryRepository, historyReloadKey, externalStreaming = false, agentChatSurface = "app", }, ref) {
|
|
1350
1353
|
const thread = useThread();
|
|
1351
1354
|
const threadRuntime = useThreadRuntime();
|
|
@@ -3974,11 +3977,34 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
|
|
|
3974
3977
|
composerContextItems.length > 0 ||
|
|
3975
3978
|
showPlanModeCallout ||
|
|
3976
3979
|
showInlineMissingKeySetup);
|
|
3980
|
+
const approvalResolutionScope = threadId ?? tabId ?? "default";
|
|
3981
|
+
const [approvalResolutionState, setApprovalResolutionState] = useState(() => ({
|
|
3982
|
+
scope: approvalResolutionScope,
|
|
3983
|
+
byIdentity: new Map(),
|
|
3984
|
+
}));
|
|
3985
|
+
const getApprovalResolution = useCallback((approvalKey, toolCallId) => {
|
|
3986
|
+
if (approvalResolutionState.scope !== approvalResolutionScope) {
|
|
3987
|
+
return null;
|
|
3988
|
+
}
|
|
3989
|
+
return (approvalResolutionState.byIdentity.get(approvalResolutionIdentity(approvalKey, toolCallId)) ?? null);
|
|
3990
|
+
}, [approvalResolutionScope, approvalResolutionState]);
|
|
3991
|
+
const recordApprovalResolution = useCallback((approvalKey, resolution, toolCallId) => {
|
|
3992
|
+
setApprovalResolutionState((previous) => {
|
|
3993
|
+
const byIdentity = previous.scope === approvalResolutionScope
|
|
3994
|
+
? previous.byIdentity
|
|
3995
|
+
: new Map();
|
|
3996
|
+
const next = new Map(byIdentity);
|
|
3997
|
+
next.set(approvalResolutionIdentity(approvalKey, toolCallId), resolution);
|
|
3998
|
+
return { scope: approvalResolutionScope, byIdentity: next };
|
|
3999
|
+
});
|
|
4000
|
+
}, [approvalResolutionScope]);
|
|
3977
4001
|
// Human-in-the-loop approvals: when the user approves a paused `needsApproval`
|
|
3978
4002
|
// tool call, re-issue the turn carrying the call's approval key so the server
|
|
3979
4003
|
// gate lets that specific call run. Reuses the same append path as recovery /
|
|
3980
4004
|
// queued messages (no hand-written fetch).
|
|
3981
4005
|
const approvalCtx = useMemo(() => ({
|
|
4006
|
+
getApprovalResolution,
|
|
4007
|
+
onApprovalResolved: recordApprovalResolution,
|
|
3982
4008
|
onApprove: (approvalKey) => {
|
|
3983
4009
|
markOptimisticRunning();
|
|
3984
4010
|
appendThreadMessage({
|
|
@@ -4000,7 +4026,14 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
|
|
|
4000
4026
|
...(approvalActions?.onAlwaysAllow
|
|
4001
4027
|
? { onAlwaysAllow: approvalActions.onAlwaysAllow }
|
|
4002
4028
|
: {}),
|
|
4003
|
-
}), [
|
|
4029
|
+
}), [
|
|
4030
|
+
appendThreadMessage,
|
|
4031
|
+
execMode,
|
|
4032
|
+
getApprovalResolution,
|
|
4033
|
+
markOptimisticRunning,
|
|
4034
|
+
approvalActions,
|
|
4035
|
+
recordApprovalResolution,
|
|
4036
|
+
]);
|
|
4004
4037
|
return (_jsx(CheckpointContext.Provider, { value: checkpointCtx, children: _jsx(MessageActionsContext.Provider, { value: messageActionsCtx, children: _jsx(ApprovalContext.Provider, { value: approvalCtx, children: _jsx(ChatRunDurationContext.Provider, { value: lastChatRunDurationMs, children: _jsx(ServerRunActiveContext.Provider, { value: serverRunActive, children: _jsx(ChatRunningContext.Provider, { value: showRunningInUI, children: _jsx(TextStreamingContext.Provider, { value: textStreaming, children: _jsxs("div", { "data-agent-empty-state": centeredEmptyState
|
|
4005
4038
|
? "centered"
|
|
4006
4039
|
: compactMissingKeyEmptyState
|
|
@@ -13,6 +13,7 @@ export type AgentChatSurfaceKind =
|
|
|
13
13
|
| "dev-frame"
|
|
14
14
|
/** Chat hosted by Desktop for a local app with explicit code access. */
|
|
15
15
|
| "desktop";
|
|
16
|
+
export declare const BACKGROUND_FOLLOW_ATTACH_WATCHDOG_MS = 90000;
|
|
16
17
|
export declare const BACKGROUND_FOLLOW_IDLE_TIMEOUT_MS = 210000;
|
|
17
18
|
export declare const MAX_FOLLOWED_BACKGROUND_RUNS = 24;
|
|
18
19
|
export declare const MAX_BACKGROUND_FOLLOW_WALL_TIME_MS: number;
|
|
@@ -96,6 +96,10 @@ const STARTUP_RESPONSE_TIMEOUT_MS = 45_000;
|
|
|
96
96
|
// reports that the self-dispatch itself failed before a successor claimed the
|
|
97
97
|
// run, the existing client auto-continue POST remains the fallback.
|
|
98
98
|
const BACKGROUND_FOLLOW_POLL_INTERVAL_MS = 1_000;
|
|
99
|
+
// This watchdog belongs to a read-only reattach, not to the server run. A
|
|
100
|
+
// shorter reader window lets the follow loop re-poll `/runs/active` while a
|
|
101
|
+
// completed run is still inside the server's terminal replay window.
|
|
102
|
+
export const BACKGROUND_FOLLOW_ATTACH_WATCHDOG_MS = 90_000;
|
|
99
103
|
// How long the follow loop tolerates seeing NO active run for this turn before
|
|
100
104
|
// treating the turn as ended. The server pre-inserts the successor row before
|
|
101
105
|
// the old chunk completes, so a healthy chain never shows an idle gap; allow a
|
|
@@ -1691,11 +1695,12 @@ export function createAgentChatAdapter(options) {
|
|
|
1691
1695
|
preparingActionStatesByRun.set(id, state);
|
|
1692
1696
|
return state;
|
|
1693
1697
|
};
|
|
1694
|
-
const currentSSEOptions = () => ({
|
|
1698
|
+
const currentSSEOptions = (overrides = {}) => ({
|
|
1695
1699
|
durableBackgroundRun: currentRunDispatchMode?.startsWith("background") === true,
|
|
1696
1700
|
...(runId
|
|
1697
1701
|
? { preparingActionState: preparingActionStateForRun(runId) }
|
|
1698
1702
|
: {}),
|
|
1703
|
+
...overrides,
|
|
1699
1704
|
});
|
|
1700
1705
|
const captureChatClientError = (error, phase, extra = {}) => {
|
|
1701
1706
|
captureError(error, {
|
|
@@ -2102,7 +2107,10 @@ export function createAgentChatAdapter(options) {
|
|
|
2102
2107
|
rememberRunSeq(seq);
|
|
2103
2108
|
if (threadId)
|
|
2104
2109
|
updateActiveRunSeq(seq);
|
|
2105
|
-
}, runId, currentSSEOptions(
|
|
2110
|
+
}, runId, currentSSEOptions({
|
|
2111
|
+
noProgressTimeoutMs: BACKGROUND_FOLLOW_ATTACH_WATCHDOG_MS,
|
|
2112
|
+
actionPreparationStallTimeoutMs: BACKGROUND_FOLLOW_ATTACH_WATCHDOG_MS,
|
|
2113
|
+
}))) {
|
|
2106
2114
|
yield withRequestModeMetadata(result);
|
|
2107
2115
|
}
|
|
2108
2116
|
// readSSEStream returned normally: a terminal done/error was
|
|
@@ -31,6 +31,7 @@ export declare function markdownUrlTransform(value: string): string;
|
|
|
31
31
|
export declare function extractCodeText(child: React.ReactNode): string;
|
|
32
32
|
export declare const markdownComponents: {
|
|
33
33
|
a(props: React.AnchorHTMLAttributes<HTMLAnchorElement>): React.JSX.Element;
|
|
34
|
+
table(props: React.TableHTMLAttributes<HTMLTableElement>): React.JSX.Element;
|
|
34
35
|
pre(props: React.HTMLAttributes<HTMLPreElement>): React.JSX.Element;
|
|
35
36
|
};
|
|
36
37
|
export declare function renderMarkdownToClipboardHtml(markdown: string): string | null;
|
|
@@ -158,6 +158,10 @@ export const markdownComponents = {
|
|
|
158
158
|
}
|
|
159
159
|
return (_jsxs("a", { href: href, target: "_blank", rel: "noreferrer", className: cn(CTA_BUTTON_CLASSES, className), ...rest, children: [_jsx("span", { children: children }), _jsx(IconExternalLink, { size: 13, strokeWidth: 2, "aria-hidden": "true" })] }));
|
|
160
160
|
},
|
|
161
|
+
table(props) {
|
|
162
|
+
const { children, ...rest } = props;
|
|
163
|
+
return (_jsx("div", { className: "agent-markdown-table-wrap", children: _jsx("table", { ...rest, children: children }) }));
|
|
164
|
+
},
|
|
161
165
|
pre(props) {
|
|
162
166
|
const { children, ...rest } = props;
|
|
163
167
|
if (React.isValidElement(children)) {
|
|
@@ -97,6 +97,7 @@ export declare function shouldShowAssistantWorkSummary({ isLast, isComplete, has
|
|
|
97
97
|
hasUnresolvedTool: boolean;
|
|
98
98
|
chatRunning: boolean;
|
|
99
99
|
}): boolean;
|
|
100
|
+
export declare function getAssistantWorkSummaryDurationMs(durationMs: number | null | undefined, groupStartIndex: number, firstWorkPartIndex: number): number | null | undefined;
|
|
100
101
|
export declare function isAlwaysVisibleAssistantTool(part: {
|
|
101
102
|
type?: unknown;
|
|
102
103
|
toolName?: unknown;
|
|
@@ -667,6 +667,9 @@ export function shouldShowAssistantWorkSummary({ isLast, isComplete, hasCollapsi
|
|
|
667
667
|
// disclosure state to the default-open value on every new submission.
|
|
668
668
|
return isComplete || !isLast;
|
|
669
669
|
}
|
|
670
|
+
export function getAssistantWorkSummaryDurationMs(durationMs, groupStartIndex, firstWorkPartIndex) {
|
|
671
|
+
return groupStartIndex === firstWorkPartIndex ? durationMs : null;
|
|
672
|
+
}
|
|
670
673
|
function ReasoningMessagePart() {
|
|
671
674
|
const part = useMessagePartReasoning();
|
|
672
675
|
const partRuntime = useMessagePartRuntime();
|
|
@@ -958,6 +961,11 @@ export function AssistantMessage() {
|
|
|
958
961
|
msgContent.some((p, index) => !isCallAgentToolCallShadowed(msgContent, index) &&
|
|
959
962
|
(p.type !== "tool-call" || p.activity !== true) &&
|
|
960
963
|
isCollapsibleAssistantWorkPart(p));
|
|
964
|
+
const firstWorkPartIndex = Array.isArray(msgContent)
|
|
965
|
+
? msgContent.findIndex((p, index) => !isCallAgentToolCallShadowed(msgContent, index) &&
|
|
966
|
+
(p.type !== "tool-call" || p.activity !== true) &&
|
|
967
|
+
isCollapsibleAssistantWorkPart(p))
|
|
968
|
+
: -1;
|
|
961
969
|
const shadowedToolCallIds = Array.isArray(msgContent)
|
|
962
970
|
? shadowedCallAgentToolCallIds(msgContent)
|
|
963
971
|
: new Set();
|
|
@@ -979,7 +987,7 @@ export function AssistantMessage() {
|
|
|
979
987
|
});
|
|
980
988
|
if (!showSummary)
|
|
981
989
|
return _jsx(_Fragment, { children: children });
|
|
982
|
-
return (_jsx(WorkedForSummary, { durationMs: capturedDurationMs ?? persistedDurationMs, defaultOpen: hasCustomUi, autoCollapse: animateCollapse && !hasCustomUi, children: children }));
|
|
990
|
+
return (_jsx(WorkedForSummary, { durationMs: getAssistantWorkSummaryDurationMs(capturedDurationMs ?? persistedDurationMs, part.indices[0] ?? -1, firstWorkPartIndex), defaultOpen: hasCustomUi, autoCollapse: animateCollapse && !hasCustomUi, children: children }));
|
|
983
991
|
}
|
|
984
992
|
case "group-ran-tools": {
|
|
985
993
|
const toolCount = part.indices.filter((index) => msgContent?.[index]?.type === "tool-call").length;
|
|
@@ -24,9 +24,17 @@ export declare function ToolCallStackMotion({ children, className, }: {
|
|
|
24
24
|
* provided, and "Always allow" only renders when `onAlwaysAllow` is provided
|
|
25
25
|
* — both are additive so existing action-approval consumers are unaffected.
|
|
26
26
|
*/
|
|
27
|
+
export type ApprovalResolution = "approved" | "denied";
|
|
27
28
|
export type ApprovalContextValue = {
|
|
28
29
|
/** Re-issue the turn so the server runs the approved call. */
|
|
29
30
|
onApprove: (approvalKey: string) => void;
|
|
31
|
+
/**
|
|
32
|
+
* Keep the visible resolution stable while the chat repository refreshes or
|
|
33
|
+
* remounts the message containing this approval card.
|
|
34
|
+
*/
|
|
35
|
+
onApprovalResolved?: (approvalKey: string, resolution: ApprovalResolution, toolCallId?: string) => void;
|
|
36
|
+
/** Read a resolution retained by the owning chat surface. */
|
|
37
|
+
getApprovalResolution?: (approvalKey: string, toolCallId?: string) => ApprovalResolution | null;
|
|
30
38
|
/**
|
|
31
39
|
* Optional host hook invoked in addition to the local "denied" state, e.g.
|
|
32
40
|
* so a Code session can also resolve its own pending approval as denied.
|