Plug-In: Step-List Generator
REQUIRES: macOS 26, iOS 26, iPados 26, visionOS 26 • OmniOutliner 6.0+
This plug-in uses the on-device Apple Foundation Models (AFM) frameworks to generate an outline in OmniOutliner based upon the steps required to perform the prompted task.
Related Links: AFM and Omni Automation documentation • AFM Plug-In Collection
AI • Step-List Generator
/*{"type": "action","targets": ["omnioutliner"],"author": "Otto Automator","identifier": "com.omni-automation.oo.step-list-generator","version": "1.0","description": "This plug-in will display a text input, into which you enter a prompt for the Apple Foundation Model requesting the steps and sub-steps for performing a specific task. A resulting outline is appended to the existing document.","label": "AI • Step List Generator","shortLabel": "AI Step List","paletteLabel": "AI Step List","image": "apple.intelligence"}*/(() => {var preferences = new Preferences() // NO ID = PLUG-IN IDconst addResponseItemToParent = (responseItem, parent) => {newRow = parent.addChild(null,item => {item.topic = responseItem["step-title"]item.note = responseItem["step-description"]});return newRow};const insertResponseItems = (responseItems, parent) => {responseItems.forEach(responseItem => {newRow = addResponseItemToParent(responseItem, parent)if (responseItem['sub-steps']){insertResponseItems(responseItem['sub-steps'], newRow);}});};const action = new PlugIn.Action(async function(selection, sender){try {storedPrompt = preferences.readString("storedPrompt")if(!storedPrompt){storedPrompt = "Provide the steps for XXXXX"}shouldUsePasteboard = preferences.readBoolean("shouldUsePasteboard")if(!shouldUsePasteboard instanceof Boolean){shouldUsePasteboard = false}inputForm = new Form()textField = new Form.Field.String("textInputValue",null,storedPrompt)checkSwitchField = new Form.Field.Checkbox("shouldUsePasteboard","Use clipboard text for prompt",shouldUsePasteboard)inputForm.addField(textField)inputForm.addField(checkSwitchField)inputForm.validate = function(formObject){shouldUsePasteboard = formObject.values["shouldUsePasteboard"]if(shouldUsePasteboard){if(!Pasteboard.general.hasStrings){throw "No text on clipboard"}return true}textValue = formObject.values["textInputValue"]textStatus = (textValue && textValue.length > 0) ? true:falsereturn textStatus}formPrompt = "Enter prompt:"formObject = await inputForm.show(formPrompt, "Continue")shouldUsePasteboard = formObject.values["shouldUsePasteboard"]console.log("PROMPT:", prompt)if(shouldUsePasteboard){var prompt = Pasteboard.general.stringpreferences.write("shouldUsePasteboard", true)} else {var prompt = formObject.values["textInputValue"]preferences.write("shouldUsePasteboard", false)}preferences.write("storedPrompt", prompt)console.log("PROMPT:", prompt)const schema = LanguageModel.Schema.fromJSON({arrayOf: {name: "step-schema",properties: [{name: "step-title",isOptional: false},{name: "step-description",isOptional: false},{name: "sub-steps",description: "A breakdown of steps.",isOptional: true,schema: {arrayOf: {referenceTo: "step-schema"},minimumElements: 1}}]}})session = new LanguageModel.Session()console.log("Begin query…")responseStr = await session.respondWithSchema(prompt, schema)console.log("Processing response…")responseObj = JSON.parse(responseStr)console.log(JSON.stringify(responseObj, null, 2))insertResponseItems(responseObj, rootItem)document.editors[0].rootNode.children.forEach(node => {node.expand(true)node.expandNote(true)})}catch(err){if(!err.causedByUserCancelling){console.error(err.name, err.message)new Alert(err.name, err.message).show()}}});action.validate = function(selection, sender){return (Device.current.operatingSystemVersion.atLeast(new Version("26")))};return action;})();