Add remark-math + rehype-katex plugins to render inline ($...$) and
display ($$...$$) math expressions. Includes dark mode CSS overrides,
streaming block splitting for math fences, and math range exclusion
in link preprocessing.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Web tools are always available, so the conditional branching was
unnecessary. Data section now always includes the dynamic evidence
decision guidance.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The finance-decisioner used hardcoded keyword matching and arbitrary
scoring weights to decide evidence plans — the LLM reading the
improved SKILL.md already makes this decision more intelligently.
Removes: finance-decisioner.ts, its tests, runner.ts integration
(applyFinanceResearchGuidance, saveFinanceDecisionMeta,
rebuildSystemPromptWithExtra shim), and researchDecision from
session meta.
Keeps: SKILL.md improvements, sections.ts dynamic data/web guidance.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
electron-updater is a CommonJS module — ESM named imports fail at
runtime. Switch to default import with destructuring.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The heartbeat runner used agent.write() (normal write), which persisted
both the heartbeat prompt and HEARTBEAT_OK response as regular messages
visible in the UI chat history.
Switch to runInternalForResult() — a new AsyncAgent method that runs
via runInternal() (messages marked internal: true, rolled back from
in-memory state). This hides both the heartbeat prompt and response
from the UI entirely, while still persisting to JSONL for diagnostics.
The previous commit's event-stream heartbeat ACK filter remains as a
defense-in-depth layer for edge cases.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The heartbeat runner uses agent.write() (normal write), so heartbeat
ACK responses like "HEARTBEAT_OK" were not suppressed by the internal
run filter and leaked into the desktop UI chat. The Gateway path was
already fixed (Hub has delayed-start + isHeartbeatAckEvent filtering),
but the local Desktop path through AsyncAgent had no such filtering.
Add createFilteredHandler() to AsyncAgent that buffers message_start
for assistant messages and checks subsequent events with
isHeartbeatAckEvent(). Pure heartbeat ACKs are suppressed end-to-end;
all other messages are forwarded normally.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Changed forwardAssistant from false to true in sendAnnounceDirect() so
the assistant's summary response is streamed to the desktop UI in
real-time. The announcement prompt stays internal (hidden from UI), but
the user now sees the completion notification.
Previously, persistAssistantSummary saved the response to JSONL but
never emitted events to the UI subscriber, leaving users with no
visible feedback after subagent tasks completed.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
setProvider() updated toolsOptions.provider but didn't reload tool
instances. The sessions_spawn tool captured the old provider in its
closure at creation time, causing subagents to inherit a stale provider.
Now calls resolveTools() + setTools() after updating toolsOptions so
sessions_spawn gets a fresh closure with the correct provider.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add an `announce` parameter to sessions_spawn that controls when findings
are delivered to the parent agent:
- "immediate" (default): announce per-completion (existing behavior)
- "silent": defer until ALL silent runs from the same requester complete,
then deliver ONE coalesced announcement with all findings
This enables workflows like "spawn 10 parallel subagents to collect data,
then summarize everything at once" without intermediate results.
Changes:
- types.ts: add `announce` field to SubagentRunRecord & RegisterSubagentRunParams
- sessions-spawn.ts: add `announce` parameter to tool schema
- registry.ts: split checkAndAnnounce into immediate/silent groups,
extract announceGroup helper, use count-match guard for silent readiness
- sections.ts: add announce mode guidance to system prompt
- registry.test.ts: add silent mode tests (field storage, group isolation)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extract SILENT_REPLY_TOKEN and isSilentReplyText() into a shared
module. Detects NO_REPLY at the start or end of text (with optional
whitespace/punctuation) to filter out silent announcement responses
that should not be forwarded to the user.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Document the full subagent lifecycle: spawn, concurrency queue,
execution, completion handling, two-tier announcement delivery,
and record archival. Include provider inheritance chain and
error propagation diagrams.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add error reporting rule to subagent system prompt: subagents must
explicitly report tool failures and missing credentials in their
final message. Add timeout guidelines to parent system prompt with
recommended values by task complexity (10-30 min).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When subagents are still running, sessions_list now returns an
explicit instruction telling the LLM not to poll again and wait
for automatic result delivery. Normalizes status display to
uppercase ([RUNNING], [OK], [ERROR]).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Pass parent's resolvedProvider through the tool chain (tools.ts →
sessions-spawn.ts → hub.createSubagent) so subagents use the same
LLM provider as the parent. Previously subagents fell back to the
hardcoded default provider, causing API key errors.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace immediate record deletion with archiveAtMs-based deferred
cleanup (60min retention). This keeps records queryable via
sessions_list after completion. Add sweeper to clean expired records.
Check childAgent.lastRunError after waitForIdle to detect failed runs
that resolve the promise without throwing.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add isRunning flag to Agent (runner.ts) for detecting active runs.
Add lastRunError to AsyncAgent for propagating child run errors to
the registry. Fix duplicate message emission in writeInternal by
resetting forwardInternalAssistant before persistAssistantSummary.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add announce-queue.ts for batching nearby subagent completions with
debounce (1s) and collect mode. Implement two-tier delivery in
announce.ts: queue when parent is busy, writeInternal when idle.
All delivery uses writeInternal() to mark messages as internal,
preventing announcement bubbles from appearing in the UI.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Display the label (or truncated task) as subtitle for SpawnSession tool
calls, so users can see what each spawned session is working on.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add chart icon, smart subtitle (shows action + ticker, e.g. "price_snapshot AAPL"),
and running state label for the data tool in the tool call UI component.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Use credentialManager.getToolConfig("data") as the primary source for
the Financial Datasets API key, with FINANCIAL_DATASETS_API_KEY env var
as fallback. Also add data tool entry to the credentials template.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- finance-research: guides agent on financial data retrieval and analysis
workflows using the data tool
- dcf-valuation: 8-step DCF valuation workflow with sector WACC reference
data, sensitivity analysis, and validation checks
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Introduces a `data` tool that provides structured access to the Financial
Datasets API (financialdatasets.ai). Supports 18 finance actions covering
stock prices, financial statements, key metrics, SEC filings, analyst
estimates, insider trades, news, and crypto data.
Designed as a stable interface — the backend can be swapped from direct
API calls to a Multica Data Service without changing the tool schema.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implement one-click desktop auto-update with version checking, download progress, and automatic installation. Includes toast notification UI in bottom-right corner showing update status (checking, available, downloading, ready, or error).
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Add description, author, and homepage fields to package.json
required by electron-builder when building .deb packages on Linux CI.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Change productName from "YourAppName" to "Multica"
- Change appId from "YourAppID" to "com.multica.app"
- Add app icons (icns, ico, png) for all platforms
- Disable hardenedRuntime to fix ad-hoc signing on ARM Macs
- Add build:desktop script to root package.json
- Simplify desktop .gitignore with !build/ exception
- Remove unused asarUnpack and entitlements config
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
completeOnboarding() only set completed=true but never cleared the
forceOnboarding flag, causing OnboardingGuard to redirect back to
onboarding in an infinite loop when --force-onboarding was used.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
setProvider() updated the resolved provider and model but did not
rebuild the system prompt, so the runtime info line still showed the
old provider/model (e.g. claude-code/claude-opus-4-6) after switching.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Previously, configured providers only showed a checkmark with no way to
reconfigure them. Now shows a "Reconfigure" button alongside the checkmark.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Registry model IDs used hyphens (claude-sonnet-4-5) but pi-ai expects
dots (claude-sonnet-4.5). Also adds a fallback model config for OpenRouter
models not in pi-ai's registry, since OpenRouter supports thousands of models.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add min-w-0 to SamplePrompt text container so truncate works in
flex layout. Always show ChatView when agent is ready so the message
input is visible (ChatView has its own empty state).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove strict model validation from provider:set IPC handler that
rejected custom models not in the static registry list (broke OpenRouter
with user-typed models). Add error display to setup page.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Use Zustand persist middleware with localStorage to remember onboarding
completion across app restarts. Only the completed flag is persisted;
transient UI state resets each launch. Add --force-onboarding CLI flag
to re-show onboarding even when already completed.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove Combobox component and use a plain text input for model name,
allowing users to enter any model identifier manually.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Save & Test flow: saves API key, then sends a minimal prompt to verify
the provider is reachable. Shows phase-based status (saving/testing/
success/error) with auto-close on success.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>