chore: get surrounding context even when nothing is selected

This commit is contained in:
nchopra 2026-01-15 17:08:04 +05:30
parent c0dbc3c26f
commit c7a8571d0c
4 changed files with 35 additions and 26 deletions

View file

@ -134,8 +134,8 @@ export function constructFormatterPrompt(context: FormatParams["context"]): {
const parts = [SYSTEM_PROMPT];
// Add vocabulary context if available
if (vocabulary && vocabulary.size > 0) {
const vocabTerms = Array.from(vocabulary.keys()).join(", ");
if (vocabulary && vocabulary.length > 0) {
const vocabTerms = vocabulary.join(", ");
parts.push(`\nCustom vocabulary to use for corrections: ${vocabTerms}`);
}

View file

@ -544,7 +544,7 @@ export class TranscriptionService {
meta: {
sessionId,
source: session.context.sharedData.audioMetadata?.source,
vocabularySize: session.context.sharedData.vocabulary?.size || 0,
vocabularySize: session.context.sharedData.vocabulary?.length || 0,
formattingStyle:
session.context.sharedData.userPreferences?.formattingStyle,
},
@ -604,7 +604,7 @@ export class TranscriptionService {
vad_enabled: !!this.vadService,
session_type: "streaming",
language: session.context.sharedData.userPreferences?.language || "en",
vocabulary_size: session.context.sharedData.vocabulary?.size || 0,
vocabulary_size: session.context.sharedData.vocabulary?.length || 0,
});
this.streamingSessions.delete(sessionId);

View file

@ -180,49 +180,58 @@ class AccessibilityContextService {
return chain
}
static let MAX_CONTEXT_LENGTH = 500
static func getTextSelection(element: AXUIElement) -> TextSelection? {
// Get selected text
guard let selectedText = getAttributeValue(element: element, attribute: kAXSelectedTextAttribute),
!selectedText.isEmpty else {
return nil
}
// Get full content
// Get full content first - we need this to provide context
let fullContent = getAttributeValue(element: element, attribute: kAXValueAttribute)
// Get selection range
// Get selection/cursor range
var selectionRange: SelectionRange? = nil
var rangeValue: CFTypeRef?
let rangeError = AXUIElementCopyAttributeValue(element, kAXSelectedTextRangeAttribute as CFString, &rangeValue)
if rangeError == .success, let axValue = rangeValue {
var range = CFRange()
if AXValueGetValue(axValue as! AXValue, .cfRange, &range) {
selectionRange = SelectionRange(length: Int(range.length), location: Int(range.location))
}
}
// Calculate pre and post selection text
// If we have no cursor/selection position and no content, return nil
guard selectionRange != nil || fullContent != nil else {
return nil
}
// Get selected text (may be empty if just cursor position)
let selectedText = getAttributeValue(element: element, attribute: kAXSelectedTextAttribute)
// Calculate pre and post selection/cursor text
var preSelectionText: String? = nil
var postSelectionText: String? = nil
if let fullContent = fullContent, let range = selectionRange {
let nsString = fullContent as NSString
// Pre-selection text: last MAX_CONTEXT_LENGTH chars before cursor/selection
if range.location > 0 {
let preRange = NSRange(location: 0, length: range.location)
let preLength = min(range.location, MAX_CONTEXT_LENGTH)
let preStart = range.location - preLength
let preRange = NSRange(location: preStart, length: preLength)
preSelectionText = nsString.substring(with: preRange)
}
// Post-selection text: first MAX_CONTEXT_LENGTH chars after cursor/selection
let postStart = range.location + range.length
if postStart < nsString.length {
let postRange = NSRange(location: postStart, length: nsString.length - postStart)
let postLength = min(nsString.length - postStart, MAX_CONTEXT_LENGTH)
let postRange = NSRange(location: postStart, length: postLength)
postSelectionText = nsString.substring(with: postRange)
}
}
let isEditable = isElementEditable(element: element)
return TextSelection(
fullContent: fullContent,
isEditable: isEditable,

View file

@ -29,10 +29,10 @@ const FocusedElementInfoSchema = z.object({
});
const TextSelectionInfoSchema = z.object({
selectedText: z.string(),
selectedText: z.string().nullable(), // Nullable when only cursor position is available (no selection)
fullContent: z.string().nullable(),
preSelectionText: z.string().nullable(),
postSelectionText: z.string().nullable(),
preSelectionText: z.string().nullable(), // Last 500 chars before cursor/selection (closest to cursor)
postSelectionText: z.string().nullable(), // First 500 chars after cursor/selection (closest to cursor)
selectionRange: SelectionRangeSchema.nullable(),
isEditable: z.boolean(),
});