Using Dialog Toolkit Plus with DT results in "NSThread doesn’t understand the “isMainThread” message"

NSThread doesn’t understand the “isMainThread” message.

I’m a bit lost fixing the error above. :confounded_face:

I searched the web and found some threads - e.g. Dialog Toolkit Plus 1.1.3 'NSThread doesn't understand the "isMainThread" message.' - AppleScript | Mac OS X - MacScripter - about it, but none really helped. It happens from time to time, but at some times it’s quite persistent. Working on it for several months now, I really want to get rid of it. Every time, I think it’s fixed, it came up again after some minor changes to the script.:enraged_face:

I run the script from the external scripts menu.

The scripts expect to be stored here:

scripts.zip (169.2 KB)

-- script
~/Library/Scripts/Applications/DEVONthink/_Review documents.scpt

-- libraries
~/Library/Script Libraries/fx-devonthink-base.scpt
~/Library/Script Libraries/fx-devonthink-ai.scpt
~/Library/Script Libraries/fx-review-documents-rules.scpt

-- script used as library
~/Library/Scripts/Applications/DEVONthink/_Rename record with AI.scpt

At some point I thought:

  • Wrapping tell […] endwas the problem
  • The length of the _Review-script was the problem
  • Maybe loading external scripts make AppleScript spawn a thread

What really made it persistent: Load an external script/library in a property.

Loading external scripts with the following code, works around caching of AppleScripts which is quite handy. This allows to change the rules I use without closing/opening DT. So this is something I really hesitate to get rid of.

on getMetadataForRecord(theRecord, thisYear, isDev)
	local scriptName
	set scriptName to "fx-review-documents-rules"
	
	local scriptPath
	set scriptPath to (system attribute "HOME") & globalLibrariesPath & scriptName & ".scpt"
	
	local scriptHandler
	set scriptHandler to load script (POSIX file scriptPath as alias)
	
	-- use rules to get metadata about file
	-- default is missing value if no rule matches
	local recordMetadata
	set recordMetadata to scriptHandler's getMetadataForRecord(theRecord, thisYear, isDev)
	
	return recordMetadata
end getMetadataForRecord

Anyway, I will try to build a script without any of MY external dependencies and will see what happens. Better a cached script, than a non-functional one.

If one tries the dialog with the AI renaming:

  • Make sure you’ve got LM Studio set up
  • Get mistral-small as model (Thanks @BLUEFROG, best results so far)
  • Setup templates db with Meine Prompts group at top
  • Add prompt Meine Prompts > _Rename record with AI.scpt.txt
  • OR: change the scripts accordingly

Content of prompt:

You are a document renaming AI. Extract content and generate standardized German filenames in JSON format only.
## Analysis Steps:
1. **Extract Date** (priority order):
   - Official document date → Receipt date → RECORD_CREATED_DATE → CURRENT_DATE
2. **Identify**:
   - Entity: Organization/sender name
   - Document type: Invoice, contract, receipt, etc.
   - Key details: Reference numbers, descriptions
3. **Format Components**:
   - Use PascalCase, no spaces/special characters
   - Max lengths: Entity (25), Description (30)
   - Translate non-German text to German
## Output JSON Only:
```json
{
  \"new_filename\": \"string\",
  \"new_date\": \"YYYY-MM-DD\",
  \"topic\": \"string\", 
  \"subtopic\": \"string\",
  \"descriptor\": \"string\",
  \"doc_type\": \"enum(rechnung, vertrag, quittung, versicherungspolice, mietvertrag, garantieschein, steuerbescheid, kontoauszug, kreditvertrag, kostenvoranschlag, bescheinigung, gehaltsabrechnung, vollmacht, mahnung, lieferschein, bestellung, angebot, rechtsanwalt_schreiben, gerichtsbeschluss, urkunde, amtsbescheid, anderes_dokument)\"
}
```
**Filename format:** [topic]-[subtopic]-[descriptor]-[doc_type]
**Character rules:** A-Z, a-z, 0-9, hyphens, underscores only. No explanation text.

Asked for help at Dialog Toolkit Plus 1.1.3 'NSThread doesn't understand the "isMainThread" message.' - #5 by david_developer - AppleScript | Mac OS X - MacScripter as well.

Not sure, if this really helps others, but anyway:

For some reason it see the error more often, if I store large portions of data in global variables - like scripts with load script.

In one of my scripts using Dialog Toolkit, I stored a larger dictionary in a global variable. After adding another entry, the script constantly fails. After removing it, it succeeded again.

For my use case, I got rid of that error (for now) by moving away from properties holding “large” amount of data.

Failing abbreviated example

	property globalpresets : {¬
		{presetTitle:"Global: No preset", addYearlyLocation:true, basePath:"", databaseName:"", addTags:{}, companyName:"", taxYear:""}, ¬
		{presetTitle:"Global: No rule", addYearlyLocation:false, basePath:"/_Review/.NORULE", databaseName:"Inbox", addTags:{}, companyName:"", taxYear:""}}

I moved to a solution which uses a plist file which is stored in a temporary directory. Hopefully, the error is gone with that move.

This also addresses a problem accessing global variables from updateOtherFields:sender. No sure why, but they appear to exist in a different global namespace and appear to be empty if the code from :sender access already defined ones.

-- example for recordMetadata -- {addYearlyLocation:false, basePath:"/Tipps/Assets/", databaseName:"knowledge", addTags:{"wissen", "tipp"}, companyName:"", askUser:false, createdAt:createdAt}

--- setup
my createTempPlist(recordMetadata, isDev)
---

--- consumer by using buildDefaultPreset()
on updateOtherFields:sender
	try
		local defaultPreset
		set defaultPreset to my buildDefaultPreset(true)
		
		-- set index of selected dropdown item
		local selectedPresetIndex
		set selectedPresetIndex to (my presetsPopup's indexOfSelectedItem() as integer) + 1
		
		local presets
		set presets to my getDialogPresets()
		set presets to {defaultPreset} & (items 2 thru -1 of presets)
		
		local selectedPreset
		set selectedPreset to item selectedPresetIndex of presets
		
		-- get values for selected dropdown
		local selectedCompanyName, selectedLocation, selectedTags, joinedTags, selectedDatabase, selectedaddYearlyLocation, selectedTaxYear
		set selectedCompanyName to (companyName of selectedPreset as text)
		set selectedLocation to (basePath of selectedPreset as text)
		set selectedTaxYear to (taxYear of selectedPreset as text)
		
		local selectedTags
		set selectedTags to (addTags of selectedPreset)
		
		set joinedTags to (join strings selectedTags using delimiter ",")
		
		set selectedDatabase to (databaseName of selectedPreset as text)
		set selectedaddYearlyLocation to (addYearlyLocation of selectedPreset as boolean)
		
		if selectedDatabase is "" or selectedDatabase is missing value then
			return missing value
		end if
		
		-- set values
		-- https://www.macscripter.net/t/change-elements-dynamically-using-shanes-dialog-toolkit/70409/11
		my (companyField's setStringValue:selectedCompanyName)
		my (locationPathField's setStringValue:selectedLocation)
		my (tagsField's setStringValue:joinedTags)
		my (addYearlyLocationCheckbox's setState:selectedaddYearlyLocation)
		my (taxesYearField's setStringValue:selectedTaxYear)
		
		local dbList
		set dbList to getDatabaseList()
		
		local dbIndex
		repeat with n from 1 to count of dbList
			if selectedDatabase is (item n of dbList) then
				set dbIndex to n - 1
				exit repeat
			end if
		end repeat
		
		my (databaseField's selectItemAtIndex:dbIndex)
	on error errMsg number errNum partial result partialError
		set AppleScript's text item delimiters to {return}
		-- An unknown error occurred. Resignal, so the caller
		-- can handle it, or AppleScript can display the number.
		display alert errMsg & ("Error number: ") & errNum & return & (partialError as text)
		error errMsg & ("Error number: ") & errNum & return & (partialError as text)
	end try
end updateOtherFields:
---

--- helpers
on buildDefaultPreset(isDev)
	local getTempPlistFile
	set getTempPlistFile to my getTempPlistFile(isDev)
	
	tell application id "DNtp"
		local tempPlistPath
		set tempPlistPath to path of getTempPlistFile as string
	end tell
	
	tell application "System Events"
		tell property list file tempPlistPath
			local addYearlyLocation, basePath, databaseName, addTags, companyName, taxYear
			try
				set addYearlyLocation to value of property list item "addYearlyLocation"
			end try
			
			try
				set basePath to value of property list item "basePath"
			on error
				set basePath to globalReviewGroupLocation & "/.NORULE"
			end try
			
			try
				set databaseName to value of property list item "databaseName"
			on error
				set databaseName to "Inbox"
			end try
			
			try
				set addTags to value of property list item "addTags"
			on error
				set addTags to {}
			end try
			
			try
				set companyName to value of property list item "companyName"
			on error
				set companyName to ""
			end try
			
			try
				set taxYear to value of property list item "taxYear"
			on error
				set taxYear to ""
			end try
		end tell
	end tell
	
	local defaultPreset
	set defaultPreset to {presetTitle:"Global: No preset", addYearlyLocation:addYearlyLocation, basePath:basePath, databaseName:databaseName, addTags:addTags, companyName:companyName, taxYear:taxYear}
	
	return defaultPreset
end buildDefaultPreset

---

on getTempPlistFile(isDev)
	local plistPath
	set plistPath to my getTempPlistPath(isDev)
	
	tell application "System Events"
		try
			return property list file plistPath
		on error
			local rootDict
			set rootDict to make new property list item with properties {kind:record}
			
			local plistFile
			set plistFile to make new property list file ¬
				with properties {contents:rootDict, name:plistPath}
		end try
	end tell
	
	return plistFile
end getTempPlistFile

on getTempPlistPath(isDev)
	local tempDir
	set tempDir to my createTempDir("reviewDocuments", isDev)
	
	local plistPath
	set plistPath to my createPosixPath({tempDir, globalTempPlistName})
	
	return plistPath
end getTempPlistPath

on createTempDir(folderName, isDev)
	local tempBase
	set tempBase to path to temporary items from user domain
	
	local targetFolder
	set targetFolder to (tempBase as text) & folderName & ":"
	
	local posixTargetFolder
	set posixTargetFolder to POSIX path of targetFolder
	
	local doesFolderExist
	set doesFolderExist to (do shell script "test -d " & quoted form of posixTargetFolder & " && echo 'yes' || echo 'no'") is "yes"
	
	if not doesFolderExist then
		tell application "Finder"
			make new folder at tempBase with properties {name:folderName}
		end tell
		
		my DtLog(missing value, "DEBUG", quoted form of "Created temporary directory", {"path=" & quoted form of posixTargetFolder}, isDev)
	end if
	
	return posixTargetFolder
end createTempDir

on createTempPlist(recordMetadata, isDev)
	local plistFile
	set plistFile to getTempPlistFile(isDev)
	
	tell application "System Events"
		tell property list items of contents of plistFile
			make new property list item at end with properties {kind:boolean, name:"addYearlyLocation", value:addYearlyLocation of recordMetadata}
			make new property list item at end with properties {kind:string, name:"basePath", value:basePath of recordMetadata}
			make new property list item at end with properties {kind:string, name:"databaseName", value:databaseName of recordMetadata}
			make new property list item at end with properties {kind:string, name:"companyName", value:companyName of recordMetadata}
			make new property list item at end with properties {kind:boolean, name:"askUser", value:askUser of recordMetadata}
			make new property list item at end with properties {kind:string, name:"createdAt", value:createdAt of recordMetadata}
			make new property list item at end with properties {kind:list, name:"addTags", value:addTags of recordMetadata}
		end tell
	end tell
	
	return plistFile
end createTempPlist