Plug-In: AFM • Solar Power Example
REQUIRES: macOS 26, iOS 26, iPados 26, visionOS 26 • OmniFocus 4.8
Based upon the example in the Omni Automation API, this plug-in demonstrates interacting with the on-device Apple Foundation Model (AFM) through an Omni Automation plug-in.
It will create a new OmniFocus project containing a set of tasks representing the steps necessary to install solar power in a home.
The plug-in provides the on-device Apple Language Models (AFM) with an example JSON schema showing how to organize the response data. Once the AFM has returned the response, it is parsed to create a new multi-level project. In addition, tasks are assigned priority level though the use of mutually-exclusive tags.
Documentation
Complete documentation regarding the integration of Omni Automation with the Apple Foundation Models frameworks is available in two sections:
- Requesting and working with text-based responses, and…
- Working with schema and JSON responses
AFM • Solar Power Example
/*{"type": "action","targets": ["omnifocus"],"author": "Otto Automator","identifier": "com.omni-automation.of.solar-project-example","version": "1.1","description": "An example plug-in that uses the on-device Apple Language Model to generate an OmniFocus project detailing the steps required to add solar power to a home.","label": "AFM • Solar Project Example","shortLabel": "AFM • Solar Project","paletteLabel": "AFM • Solar Project","image": "apple.intelligence"}*/(() => {// SCHEMA FOR THE AFMvar schemaJSON = {arrayOf: {name: "step-schema",properties: [{name: "title",isOptional: false},{name: "description",isOptional: false},{name: "priority",schema: {name: "priority-schema",anyOf: [{constant: "high"},{constant: "low"}]}},{name: "substeps",description: "A breakdown of steps.",isOptional: true,schema: {arrayOf: {referenceTo: "step-schema"},minimumElements: 1}}]}}// FUNCTION FOR CREATING PROJECT USING AFM RESPONSEfunction insertJsonUnderParent(steps, parent) {steps.forEach(step => {title = step.titledescription = step.descriptionpriority = step.priorityconsole.log("Title:", title)console.log("Description:", description)console.log("Priority:", priority)task = new Task(title, parent)task.note = descriptionpriorityTag = (priority === "low") ? lowTag:highTagtask.addTag(priorityTag)console.log("Priority Tag:", priorityTag)console.log("---------------------")if (step['substeps']) {insertJsonUnderParent(step['substeps'], task);}});}function expandNotes(object, window){contentTree = window.content;node = contentTree.nodeForObject(object);node.expandNote(true);}const action = new PlugIn.Action(async function(selection, sender){try {// CREATE PROJECTproject = new Project("Thinking…")window = document.windows[0]window.perspective = Perspective.BuiltIn.Projectswindow.focus = [project]// QUERY THE ON-DEVICE APPLE LANGUAGE MODELschema = LanguageModel.Schema.fromJSON(schemaJSON)prompt = "Provide a list of steps required to add solar power to a home."session = new LanguageModel.Session()options = new LanguageModel.GenerationOptions()options.maximumResponseTokens = 4096response = await session.respondWithSchema(prompt, schema)responseJSON = JSON.parse(response)console.log(JSON.stringify(response, null, 2))// CREATE MUTUALLY-EXCLUSIVE PRIORITY TAG GROUP AS NEEDEDtagGroup = flattenedTags.byName("Priority") || new Tag("Priority")lowTag = tagGroup.tagNamed("Low") || new Tag("Low", tagGroup.beginning)highTag = tagGroup.tagNamed("High") || new Tag("High", tagGroup.beginning)tagGroup.childrenAreMutuallyExclusive = true// RENAME PROJECTproject.name = "Home Solar Project"// CREATE PROJECT HEIRARCHYinsertJsonUnderParent(response, project)// DISPLAY PROJECTproject.url.open()expandNotes(project, selection.window)}catch(err){if(project){document.windows[0].focus = []deleteObject(project)}if(!err.causedByUserCancelling){console.error(err.name, err.message)new Alert(err.name, err.message).show()}}});action.validate = function(selection, sender){// VERIFY DEVICE IS RUNNING OS26 OR NEWERcompatibility = Device.current.operatingSystemVersion.atLeast(new Version("26"))return compatibility};return action;})();