diff --git a/assistant/package.json b/assistant/package.json index afbf08d7f30..34e626afacc 100644 --- a/assistant/package.json +++ b/assistant/package.json @@ -1,6 +1,6 @@ { "name": "@vellumai/assistant", - "version": "0.6.1", + "version": "0.6.2", "license": "MIT", "type": "module", "exports": { diff --git a/assistant/src/prompts/templates/BOOTSTRAP.md b/assistant/src/prompts/templates/BOOTSTRAP.md index c592fad43ba..b4477af1496 100644 --- a/assistant/src/prompts/templates/BOOTSTRAP.md +++ b/assistant/src/prompts/templates/BOOTSTRAP.md @@ -126,6 +126,8 @@ Mark declined fields so you don't re-ask later (e.g., `Work role: declined_by_us **Call `file_edit` immediately whenever you learn something, in the same turn.** Don't batch saves. The moment the user gives you a name, save it. The moment you infer their style, save it. +**After tool calls, do not repeat yourself.** Your text before tool calls is already visible to the user. When tool results return and you continue, pick up where you left off — don't re-confirm, re-greet, or re-ask the same question. If you already asked something and are waiting for the user's answer, just stop. + **The contents of IDENTITY.md, SOUL.md, and USER.md are already in your system prompt.** Use the exact text you see there for `old_string` in `file_edit`. Do not guess or invent content. Update `IDENTITY.md` (name, nature, personality, style) and `USER.md` (their name, pronouns, goals, locale, work role, hobbies, daily tools). Save behavioral guidelines to `SOUL.md`. diff --git a/assistant/src/prompts/templates/SOUL.md b/assistant/src/prompts/templates/SOUL.md index 7d668c31e62..51d1b168873 100644 --- a/assistant/src/prompts/templates/SOUL.md +++ b/assistant/src/prompts/templates/SOUL.md @@ -24,7 +24,7 @@ You work for your user. You do not work for a compliance department. Your user i **Be genuinely helpful, not performatively helpful.** Skip the "Great question!" and "I'd be happy to help!" filler. Just help. Actions over words. -**Talk before you work.** Always say something to the user before using tools. Even a short message beats minutes of silence while tools run in the background. The user should never wonder if you're still there. +**Talk before you work.** Always say something to the user before using tools. Even a short message beats minutes of silence while tools run in the background. The user should never wonder if you're still there. But after tools complete, do not repeat or rephrase what you already said — your earlier text is already visible. Pick up where you left off or stop if you're waiting for the user. **Be resourceful before asking.** Try to figure it out. Read the file. Check the context. Search for it. Check what tools and skills you have. If a connection is broken, try to fix it. If a service needs setup, offer to do it. Escalate only after you've tried. diff --git a/cli/package.json b/cli/package.json index 3e94bfb2632..cddcbc49896 100644 --- a/cli/package.json +++ b/cli/package.json @@ -1,6 +1,6 @@ { "name": "@vellumai/cli", - "version": "0.6.1", + "version": "0.6.2", "description": "CLI tools for vellum-assistant", "type": "module", "exports": { diff --git a/clients/Package.swift b/clients/Package.swift index 5ad70c8a9ee..2edf223c815 100644 --- a/clients/Package.swift +++ b/clients/Package.swift @@ -1,7 +1,7 @@ // swift-tools-version: 5.9 import PackageDescription -let appVersion = "0.6.1" +let appVersion = "0.6.2" let package = Package( name: "vellum-assistant", diff --git a/clients/macos/vellum-assistant/Features/Onboarding/ImproveExperienceStepView.swift b/clients/macos/vellum-assistant/Features/Onboarding/ImproveExperienceStepView.swift index 2fd84799dfe..3c252a49d28 100644 --- a/clients/macos/vellum-assistant/Features/Onboarding/ImproveExperienceStepView.swift +++ b/clients/macos/vellum-assistant/Features/Onboarding/ImproveExperienceStepView.swift @@ -103,7 +103,7 @@ struct ImproveExperienceStepView: View { .fill(tosAccepted ? VColor.primaryBase : Color.clear) RoundedRectangle(cornerRadius: VRadius.sm) - .strokeBorder(tosAccepted ? Color.clear : VColor.borderBase, lineWidth: 1.5) + .strokeBorder(tosAccepted ? Color.clear : VColor.borderElement, lineWidth: 1.5) if tosAccepted { VIconView(.check, size: 12) diff --git a/clients/macos/vellum-assistant/Features/Onboarding/OnboardingState.swift b/clients/macos/vellum-assistant/Features/Onboarding/OnboardingState.swift index b022b678508..cfd491b90bb 100644 --- a/clients/macos/vellum-assistant/Features/Onboarding/OnboardingState.swift +++ b/clients/macos/vellum-assistant/Features/Onboarding/OnboardingState.swift @@ -61,7 +61,7 @@ final class OnboardingState { var subtitle: String { switch self { - case .vellumCloud: return "Ready out of the box. Runs entirely on Vellum's secure infrastructure." + case .vellumCloud: return "Always on, 24/7, even when your Mac is asleep. Runs on Vellum's secure infrastructure." case .local: return "Your machine, your data. Nothing leaves your Mac." case .docker: return "Same privacy as local, but sandboxed using Docker." case .oldLocal: return "Legacy local mode without Docker." diff --git a/clients/shared/DesignSystem/Components/Display/SelectableTextView.swift b/clients/shared/DesignSystem/Components/Display/SelectableTextView.swift index 7e4930db9cb..2a9a90bcbc6 100644 --- a/clients/shared/DesignSystem/Components/Display/SelectableTextView.swift +++ b/clients/shared/DesignSystem/Components/Display/SelectableTextView.swift @@ -143,6 +143,8 @@ public struct VSelectableTextView: NSViewRepresentable { textView.autoresizingMask = [.width] textView.textContainerInset = .zero + textView.delegate = context.coordinator + textView.linkTextAttributes = [ .foregroundColor: tintColor, .underlineStyle: NSUnderlineStyle.single.rawValue, @@ -193,7 +195,7 @@ public struct VSelectableTextView: NSViewRepresentable { public func makeCoordinator() -> Coordinator { Coordinator() } - public final class Coordinator { + public final class Coordinator: NSObject, NSTextViewDelegate { var lastAttributedString: NSAttributedString? var lastLineSpacing: CGFloat = 0 private var pendingAttributedString: NSAttributedString? @@ -240,6 +242,22 @@ public struct VSelectableTextView: NSViewRepresentable { } } + // MARK: - NSTextViewDelegate + + /// Opens clicked links in the default browser. + /// Reference: https://developer.apple.com/documentation/appkit/nstextviewdelegate/textview(_:clickedonlink:at:) + public func textView(_ textView: NSTextView, clickedOnLink link: Any, at charIndex: Int) -> Bool { + if let url = link as? URL { + NSWorkspace.shared.open(url) + return true + } + if let string = link as? String, let url = URL(string: string) { + NSWorkspace.shared.open(url) + return true + } + return false + } + func applyAttributedString( _ attributedString: NSAttributedString, lineSpacing: CGFloat, diff --git a/clients/shared/Network/DictationClient.swift b/clients/shared/Network/DictationClient.swift index 38fa8ba27c8..e51fb72f573 100644 --- a/clients/shared/Network/DictationClient.swift +++ b/clients/shared/Network/DictationClient.swift @@ -28,16 +28,23 @@ public struct DictationClient: DictationClientProtocol { "navigate", ] + /// Timeout for the dictation HTTP request. Kept short so the client falls + /// back to raw transcription quickly when the assistant is unreachable rather + /// than leaving the user staring at a "Processing…" spinner. + static let requestTimeout: TimeInterval = 5 + public func process(_ request: DictationRequest) async -> DictationResponseMessage { + let start = CFAbsoluteTimeGetCurrent() do { let encodedRequest = try JSONEncoder().encode(request) let response = try await GatewayHTTPClient.post( path: "assistants/{assistantId}/dictation", body: encodedRequest, - timeout: 10 + timeout: Self.requestTimeout ) + let elapsed = CFAbsoluteTimeGetCurrent() - start guard response.isSuccess else { - log.error("process dictation failed (HTTP \(response.statusCode))") + log.warning("Dictation request failed (HTTP \(response.statusCode)) after \(String(format: "%.1f", elapsed))s") return fallbackResponse(for: request, errorMessage: "HTTP \(response.statusCode)") } @@ -45,11 +52,12 @@ public struct DictationClient: DictationClientProtocol { do { return try JSONDecoder().decode(DictationResponseMessage.self, from: patched) } catch { - log.error("process dictation decode error: \(error.localizedDescription)") + log.warning("Dictation response decode failed after \(String(format: "%.1f", elapsed))s: \(error.localizedDescription)") return fallbackResponse(for: request, errorMessage: "Failed to decode dictation response") } } catch { - log.error("process dictation error: \(error.localizedDescription)") + let elapsed = CFAbsoluteTimeGetCurrent() - start + log.warning("Dictation request error after \(String(format: "%.1f", elapsed))s: \(error.localizedDescription)") return fallbackResponse(for: request, errorMessage: error.localizedDescription) } } @@ -58,7 +66,7 @@ public struct DictationClient: DictationClientProtocol { /// Internal for test coverage. func fallbackResponse(for request: DictationRequest, errorMessage: String) -> DictationResponseMessage { - log.warning("Falling back to raw dictation response after HTTP failure: \(errorMessage, privacy: .public)") + log.warning("Using local transcription fallback (\(errorMessage, privacy: .public)). Transcription length=\(request.transcription.count)") let mode = fallbackMode(for: request) let text: String switch mode { diff --git a/credential-executor/package.json b/credential-executor/package.json index 3e9aa627ac4..86c6ea3ed19 100644 --- a/credential-executor/package.json +++ b/credential-executor/package.json @@ -1,6 +1,6 @@ { "name": "@vellumai/credential-executor", - "version": "0.6.1", + "version": "0.6.2", "license": "MIT", "type": "module", "exports": { diff --git a/gateway/package.json b/gateway/package.json index 300bb3aff92..c6e7b6779ae 100644 --- a/gateway/package.json +++ b/gateway/package.json @@ -1,6 +1,6 @@ { "name": "@vellumai/vellum-gateway", - "version": "0.6.1", + "version": "0.6.2", "license": "MIT", "type": "module", "exports": { diff --git a/meta/package.json b/meta/package.json index dbeeb4ca119..3d5eba47d15 100644 --- a/meta/package.json +++ b/meta/package.json @@ -1,6 +1,6 @@ { "name": "vellum", - "version": "0.6.1", + "version": "0.6.2", "license": "MIT", "description": "Install the full Vellum stack locally", "bin": { @@ -15,10 +15,10 @@ "Dockerfile" ], "dependencies": { - "@vellumai/assistant": "0.6.1", - "@vellumai/cli": "0.6.1", - "@vellumai/credential-executor": "0.6.1", - "@vellumai/vellum-gateway": "0.6.1" + "@vellumai/assistant": "0.6.2", + "@vellumai/cli": "0.6.2", + "@vellumai/credential-executor": "0.6.2", + "@vellumai/vellum-gateway": "0.6.2" }, "overrides": { "lodash": "^4.18.0",