From e4d312d5e8e6478eea45ccdf4e39064ca3c68537 Mon Sep 17 00:00:00 2001 From: daboe01 Date: Wed, 26 Aug 2026 18:49:54 +0000 Subject: [PATCH] =?UTF-8?q?Deploying=20to=20gh-pages=20from=20@=20cappucci?= =?UTF-8?q?no/cappuccino@7083f7b2685d9f0b60c533136572f2fa8a585fa1=20?= =?UTF-8?q?=F0=9F=9A=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Foundation/ObjJ.environment/Foundation.sj | 485 +++++++++++++ .../CPLanguageModelChatbot/AppController.j | 657 ++++++++++++++++++ Resources/CPLanguageModelChatbot/Info.plist | 12 + Resources/CPLanguageModelChatbot/Jakefile | 94 +++ .../Resources/spinner.gif | Bin 0 -> 1434 bytes .../CPLanguageModelChatbot/index-debug.html | 103 +++ Resources/CPLanguageModelChatbot/index.html | 167 +++++ Resources/CPLanguageModelChatbot/main.j | 18 + Resources/recipes.txt | 295 ++++---- 9 files changed, 1684 insertions(+), 147 deletions(-) create mode 100644 Resources/CPLanguageModelChatbot/AppController.j create mode 100644 Resources/CPLanguageModelChatbot/Info.plist create mode 100644 Resources/CPLanguageModelChatbot/Jakefile create mode 100644 Resources/CPLanguageModelChatbot/Resources/spinner.gif create mode 100644 Resources/CPLanguageModelChatbot/index-debug.html create mode 100644 Resources/CPLanguageModelChatbot/index.html create mode 100644 Resources/CPLanguageModelChatbot/main.j diff --git a/Frameworks/Foundation/ObjJ.environment/Foundation.sj b/Frameworks/Foundation/ObjJ.environment/Foundation.sj index 34fa4a0b6..1a1158ecb 100644 --- a/Frameworks/Foundation/ObjJ.environment/Foundation.sj +++ b/Frameworks/Foundation/ObjJ.environment/Foundation.sj @@ -10693,6 +10693,491 @@ var _CPKVOInfoMake = function(anObserver, theOptions, aContext, aForwarder) { return {observer: anObserver, options: theOptions, context: aContext, forwarder: aForwarder}; }; +p;17;CPLanguageModel.jt;27581;@STATIC;1.0;i;10;CPObject.ji;10;CPString.ji;9;CPError.ji;14;CPDictionary.ji;10;CPBundle.ji;16;CPUserDefaults.jt;27463;objj_executeFile("CPObject.j", YES);objj_executeFile("CPString.j", YES);objj_executeFile("CPError.j", YES);objj_executeFile("CPDictionary.j", YES);objj_executeFile("CPBundle.j", YES);objj_executeFile("CPUserDefaults.j", YES);var CPLanguageModelSessionFallbackServiceType = "ollama", + CPLanguageModelSessionFallbackEndpoint = "http://localhost:11434/api/generate", + CPLanguageModelSessionFallbackModel = "gemma4:e4b", + CPLanguageModelSessionFallbackAPIKey = "", + CPLanguageModelSessionFallbackAPIKeyUserDefaultKey = "", + CPLanguageModelSessionEndorsesFallback = NO; + +{var the_class = objj_allocateClassPair(CPObject, "CPSystemLanguageModel"), +meta_class = the_class.isa;var sharedInstance = nil; +objj_registerClassPair(the_class); +class_addMethods(the_class, [new objj_method(sel_getUid("supportsLocaleWithCompletionHandler:"), function $CPSystemLanguageModel__supportsLocaleWithCompletionHandler_(self, _cmd, completionHandler) +{ + if (typeof window === "undefined" || !completionHandler) + { + if (completionHandler) + completionHandler(NO); + return; + } + ( async function() + { + var supported = false; + try { + if (window.ai && window.ai.languageModel) + { + var options = {expectedInputs: [{type: "text", languages: ["en"]}], expectedOutputs: [{type: "text", languages: ["en"]}]}; + if (typeof window.ai.languageModel.availability === 'function') + { + var avail = await (window.ai.languageModel.availability(options)); + supported = avail === "readily" || avail === "available" || avail === "after-download"; + } + else if (typeof window.ai.languageModel.capabilities === 'function') + { + var caps = await (window.ai.languageModel.capabilities(options)); + supported = caps.available === "readily" || caps.available === "after-download"; + } + else + { + supported = true; + } + } + else if (window.LanguageModel) + { + supported = true; + } + } + catch(e) { + supported = false; + } + completionHandler(supported); + })(); +} + +,["void","Function"])]); +class_addMethods(meta_class, [new objj_method(sel_getUid("defaultModel"), function $CPSystemLanguageModel__defaultModel(self, _cmd) +{ + if (!sharedInstance) + sharedInstance = ((___r1 = (CPSystemLanguageModel.isa.method_msgSend["alloc"] || _objj_forward)(CPSystemLanguageModel, "alloc")), ___r1 == null ? ___r1 : (___r1.isa.method_msgSend["init"] || _objj_forward)(___r1, "init")); + return sharedInstance; + var ___r1; +} + +,["id"])]); +} + +{var the_class = objj_allocateClassPair(CPObject, "CPLanguageModelSession"), +meta_class = the_class.isa;class_addIvars(the_class, [new objj_ivar("_chromeSession", "id"), new objj_ivar("_instructions", "CPString"), new objj_ivar("_fallbackServiceType", "CPString"), new objj_ivar("_fallbackEndpoint", "CPString"), new objj_ivar("_fallbackModel", "CPString"), new objj_ivar("_fallbackAPIKey", "CPString")]);objj_registerClassPair(the_class); +class_addMethods(the_class, [new objj_method(sel_getUid("chromeSession"), function $CPLanguageModelSession__chromeSession(self, _cmd) +{ + return self._chromeSession; +} + +,["id"]), new objj_method(sel_getUid("setChromeSession:"), function $CPLanguageModelSession__setChromeSession_(self, _cmd, newValue) +{ + self._chromeSession = newValue; +} + +,["void","id"]), new objj_method(sel_getUid("instructions"), function $CPLanguageModelSession__instructions(self, _cmd) +{ + return self._instructions; +} + +,["CPString"]), new objj_method(sel_getUid("setInstructions:"), function $CPLanguageModelSession__setInstructions_(self, _cmd, newValue) +{ + self._instructions = newValue; +} + +,["void","CPString"]), new objj_method(sel_getUid("fallbackServiceType"), function $CPLanguageModelSession__fallbackServiceType(self, _cmd) +{ + return self._fallbackServiceType; +} + +,["CPString"]), new objj_method(sel_getUid("setFallbackServiceType:"), function $CPLanguageModelSession__setFallbackServiceType_(self, _cmd, newValue) +{ + self._fallbackServiceType = newValue; +} + +,["void","CPString"]), new objj_method(sel_getUid("fallbackEndpoint"), function $CPLanguageModelSession__fallbackEndpoint(self, _cmd) +{ + return self._fallbackEndpoint; +} + +,["CPString"]), new objj_method(sel_getUid("setFallbackEndpoint:"), function $CPLanguageModelSession__setFallbackEndpoint_(self, _cmd, newValue) +{ + self._fallbackEndpoint = newValue; +} + +,["void","CPString"]), new objj_method(sel_getUid("fallbackModel"), function $CPLanguageModelSession__fallbackModel(self, _cmd) +{ + return self._fallbackModel; +} + +,["CPString"]), new objj_method(sel_getUid("setFallbackModel:"), function $CPLanguageModelSession__setFallbackModel_(self, _cmd, newValue) +{ + self._fallbackModel = newValue; +} + +,["void","CPString"]), new objj_method(sel_getUid("fallbackAPIKey"), function $CPLanguageModelSession__fallbackAPIKey(self, _cmd) +{ + return self._fallbackAPIKey; +} + +,["CPString"]), new objj_method(sel_getUid("setFallbackAPIKey:"), function $CPLanguageModelSession__setFallbackAPIKey_(self, _cmd, newValue) +{ + self._fallbackAPIKey = newValue; +} + +,["void","CPString"]), new objj_method(sel_getUid("initWithInstructions:"), function $CPLanguageModelSession__initWithInstructions_(self, _cmd, instructions) +{ + self = (objj_getClass("CPLanguageModelSession").super_class.method_dtable["init"] || _objj_forward)(self, "init"); + if (self) + { + self._instructions = instructions; + self._chromeSession = nil; + self._fallbackServiceType = nil; + self._fallbackEndpoint = nil; + self._fallbackModel = nil; + self._fallbackAPIKey = nil; + } + return self; +} + +,["id","CPString"]), new objj_method(sel_getUid("initWithInstructions:apiKey:"), function $CPLanguageModelSession__initWithInstructions_apiKey_(self, _cmd, instructions, apiKey) +{ + self = (self == null ? self : (self.isa.method_msgSend["initWithInstructions:"] || _objj_forward)(self, "initWithInstructions:", instructions)); + if (self) + { + self._fallbackAPIKey = apiKey; + } + return self; +} + +,["id","CPString","CPString"]), new objj_method(sel_getUid("initWithInstructions:fallbackOptions:"), function $CPLanguageModelSession__initWithInstructions_fallbackOptions_(self, _cmd, instructions, options) +{ + self = (self == null ? self : (self.isa.method_msgSend["initWithInstructions:"] || _objj_forward)(self, "initWithInstructions:", instructions)); + if (self) + { + if (options) + { + self._fallbackServiceType = (options == null ? options : (options.isa.method_msgSend["objectForKey:"] || _objj_forward)(options, "objectForKey:", "serviceType")); + self._fallbackEndpoint = (options == null ? options : (options.isa.method_msgSend["objectForKey:"] || _objj_forward)(options, "objectForKey:", "endpoint")); + self._fallbackModel = (options == null ? options : (options.isa.method_msgSend["objectForKey:"] || _objj_forward)(options, "objectForKey:", "model")); + self._fallbackAPIKey = (options == null ? options : (options.isa.method_msgSend["objectForKey:"] || _objj_forward)(options, "objectForKey:", "apiKey")); + } + } + return self; +} + +,["id","CPString","CPDictionary"]), new objj_method(sel_getUid("respondToPrompt:options:completionHandler:"), function $CPLanguageModelSession__respondToPrompt_options_completionHandler_(self, _cmd, prompt, options, completionHandler) +{ + if (CPLanguageModelSessionEndorsesFallback) + { + (self.isa.method_msgSend["_executeRemoteFallbackWithPrompt:options:completionHandler:"] || _objj_forward)(self, "_executeRemoteFallbackWithPrompt:options:completionHandler:", prompt, options, completionHandler); + return; + } + if (self._chromeSession) + { + (self.isa.method_msgSend["_executePrompt:options:completionHandler:"] || _objj_forward)(self, "_executePrompt:options:completionHandler:", prompt, options, completionHandler); + return; + } + var instructions = (self.isa.method_msgSend["instructions"] || _objj_forward)(self, "instructions"); + (CPLanguageModelSession.isa.method_msgSend["_getChromeFactoryWithCompletionHandler:"] || _objj_forward)(CPLanguageModelSession, "_getChromeFactoryWithCompletionHandler:", function(factory, error) + { + if (error) + { + (self.isa.method_msgSend["_executeRemoteFallbackWithPrompt:options:completionHandler:"] || _objj_forward)(self, "_executeRemoteFallbackWithPrompt:options:completionHandler:", prompt, options, completionHandler); + return; + } + var sessionOptions = {expectedInputs: [{type: "text", languages: ["en"]}], expectedOutputs: [{type: "text", languages: ["en"]}]}; + if (instructions) + { + sessionOptions.systemPrompt = instructions; + } + factory.create(sessionOptions).then( function(session) + { + (self.isa.method_msgSend["setChromeSession:"] || _objj_forward)(self, "setChromeSession:", session); + (self.isa.method_msgSend["_executePrompt:options:completionHandler:"] || _objj_forward)(self, "_executePrompt:options:completionHandler:", prompt, options, completionHandler); + }).catch( function(err) + { + (self.isa.method_msgSend["_executeRemoteFallbackWithPrompt:options:completionHandler:"] || _objj_forward)(self, "_executeRemoteFallbackWithPrompt:options:completionHandler:", prompt, options, completionHandler); + }); + }); +} + +,["void","CPString","id","Function"]), new objj_method(sel_getUid("respondToPrompt:onChunkReceived:completed:"), function $CPLanguageModelSession__respondToPrompt_onChunkReceived_completed_(self, _cmd, prompt, chunkHandler, completionHandler) +{ + if (CPLanguageModelSessionEndorsesFallback) + { + (self.isa.method_msgSend["_executeRemoteFallbackWithPrompt:options:completionHandler:"] || _objj_forward)(self, "_executeRemoteFallbackWithPrompt:options:completionHandler:", prompt, nil, function(res, err) + { + if (!err && chunkHandler) + chunkHandler(res); + completionHandler(res, err); + ((___r1 = (CPRunLoop.isa.method_msgSend["currentRunLoop"] || _objj_forward)(CPRunLoop, "currentRunLoop")), ___r1 == null ? ___r1 : (___r1.isa.method_msgSend["limitDateForMode:"] || _objj_forward)(___r1, "limitDateForMode:", CPDefaultRunLoopMode)); + var ___r1; + }); + return; + } + if (self._chromeSession) + { + (self.isa.method_msgSend["_executePromptStreaming:onChunkReceived:completed:"] || _objj_forward)(self, "_executePromptStreaming:onChunkReceived:completed:", prompt, chunkHandler, completionHandler); + return; + } + var instructions = (self.isa.method_msgSend["instructions"] || _objj_forward)(self, "instructions"); + (CPLanguageModelSession.isa.method_msgSend["_getChromeFactoryWithCompletionHandler:"] || _objj_forward)(CPLanguageModelSession, "_getChromeFactoryWithCompletionHandler:", function(factory, error) + { + if (error) + { + (self.isa.method_msgSend["_executeRemoteFallbackWithPrompt:options:completionHandler:"] || _objj_forward)(self, "_executeRemoteFallbackWithPrompt:options:completionHandler:", prompt, nil, function(res, err) + { + if (!err && chunkHandler) + chunkHandler(res); + completionHandler(res, err); + ((___r1 = (CPRunLoop.isa.method_msgSend["currentRunLoop"] || _objj_forward)(CPRunLoop, "currentRunLoop")), ___r1 == null ? ___r1 : (___r1.isa.method_msgSend["limitDateForMode:"] || _objj_forward)(___r1, "limitDateForMode:", CPDefaultRunLoopMode)); + var ___r1; + }); + return; + } + var options = {expectedInputs: [{type: "text", languages: ["en"]}], expectedOutputs: [{type: "text", languages: ["en"]}]}; + if (instructions) + options.systemPrompt = instructions; + factory.create(options).then( function(session) + { + (self.isa.method_msgSend["setChromeSession:"] || _objj_forward)(self, "setChromeSession:", session); + (self.isa.method_msgSend["_executePromptStreaming:onChunkReceived:completed:"] || _objj_forward)(self, "_executePromptStreaming:onChunkReceived:completed:", prompt, chunkHandler, completionHandler); + }).catch( function(err) + { + (self.isa.method_msgSend["_executeRemoteFallbackWithPrompt:options:completionHandler:"] || _objj_forward)(self, "_executeRemoteFallbackWithPrompt:options:completionHandler:", prompt, nil, function(res, err) + { + if (!err && chunkHandler) + chunkHandler(res); + completionHandler(res, err); + ((___r1 = (CPRunLoop.isa.method_msgSend["currentRunLoop"] || _objj_forward)(CPRunLoop, "currentRunLoop")), ___r1 == null ? ___r1 : (___r1.isa.method_msgSend["limitDateForMode:"] || _objj_forward)(___r1, "limitDateForMode:", CPDefaultRunLoopMode)); + var ___r1; + }); + }); + }); +} + +,["void","CPString","Function","Function"]), new objj_method(sel_getUid("destroy"), function $CPLanguageModelSession__destroy(self, _cmd) +{ + if (self._chromeSession && typeof self._chromeSession.destroy === "function") + { + self._chromeSession.destroy(); + self._chromeSession = nil; + } +} + +,["void"]), new objj_method(sel_getUid("_executePrompt:options:completionHandler:"), function $CPLanguageModelSession___executePrompt_options_completionHandler_(self, _cmd, prompt, options, completionHandler) +{ + var promptPromise = options ? self._chromeSession.prompt(prompt, options) : self._chromeSession.prompt(prompt); + promptPromise.then( function(result) + { + completionHandler(result, nil); + ((___r1 = (CPRunLoop.isa.method_msgSend["currentRunLoop"] || _objj_forward)(CPRunLoop, "currentRunLoop")), ___r1 == null ? ___r1 : (___r1.isa.method_msgSend["limitDateForMode:"] || _objj_forward)(___r1, "limitDateForMode:", CPDefaultRunLoopMode)); + var ___r1; + }).catch( function(err) + { + var cpError = (CPError.isa.method_msgSend["errorWithDomain:code:userInfo:"] || _objj_forward)(CPError, "errorWithDomain:code:userInfo:", "CPLanguageModelErrorDomain", 2, (CPDictionary.isa.method_msgSend["dictionaryWithObject:forKey:"] || _objj_forward)(CPDictionary, "dictionaryWithObject:forKey:", err.message, CPLocalizedDescriptionKey)); + completionHandler(nil, cpError); + ((___r1 = (CPRunLoop.isa.method_msgSend["currentRunLoop"] || _objj_forward)(CPRunLoop, "currentRunLoop")), ___r1 == null ? ___r1 : (___r1.isa.method_msgSend["limitDateForMode:"] || _objj_forward)(___r1, "limitDateForMode:", CPDefaultRunLoopMode)); + var ___r1; + }); +} + +,["void","CPString","id","Function"]), new objj_method(sel_getUid("_resolvedFallbackServiceType"), function $CPLanguageModelSession___resolvedFallbackServiceType(self, _cmd) +{ + return self._fallbackServiceType || CPLanguageModelSessionFallbackServiceType; +} + +,["CPString"]), new objj_method(sel_getUid("_resolvedFallbackEndpoint"), function $CPLanguageModelSession___resolvedFallbackEndpoint(self, _cmd) +{ + return self._fallbackEndpoint || CPLanguageModelSessionFallbackEndpoint; +} + +,["CPString"]), new objj_method(sel_getUid("_resolvedFallbackModel"), function $CPLanguageModelSession___resolvedFallbackModel(self, _cmd) +{ + return self._fallbackModel || CPLanguageModelSessionFallbackModel; +} + +,["CPString"]), new objj_method(sel_getUid("_resolvedFallbackAPIKey"), function $CPLanguageModelSession___resolvedFallbackAPIKey(self, _cmd) +{ + if (self._fallbackAPIKey) + return self._fallbackAPIKey; + if (CPLanguageModelSessionFallbackAPIKey) + return CPLanguageModelSessionFallbackAPIKey; + if (CPLanguageModelSessionFallbackAPIKeyUserDefaultKey) + { + var defaults = (CPUserDefaults.isa.method_msgSend["standardUserDefaults"] || _objj_forward)(CPUserDefaults, "standardUserDefaults"), + apiKey = (defaults == null ? defaults : (defaults.isa.method_msgSend["objectForKey:"] || _objj_forward)(defaults, "objectForKey:", CPLanguageModelSessionFallbackAPIKeyUserDefaultKey)); + if (apiKey) + return apiKey; + } + return ""; +} + +,["CPString"]), new objj_method(sel_getUid("_executeRemoteFallbackWithPrompt:options:completionHandler:"), function $CPLanguageModelSession___executeRemoteFallbackWithPrompt_options_completionHandler_(self, _cmd, prompt, options, completionHandler) +{ + var systemPrompt = (self.isa.method_msgSend["instructions"] || _objj_forward)(self, "instructions"), + serviceType = (self.isa.method_msgSend["_resolvedFallbackServiceType"] || _objj_forward)(self, "_resolvedFallbackServiceType"), + endpoint = (self.isa.method_msgSend["_resolvedFallbackEndpoint"] || _objj_forward)(self, "_resolvedFallbackEndpoint"), + model = (self.isa.method_msgSend["_resolvedFallbackModel"] || _objj_forward)(self, "_resolvedFallbackModel"), + apiKey = (self.isa.method_msgSend["_resolvedFallbackAPIKey"] || _objj_forward)(self, "_resolvedFallbackAPIKey"); + var reqUrl = "", + headers = {"Content-Type": "application/json"}, + payload = {}; + if (serviceType === "groq") + { + reqUrl = "https://api.groq.com/openai/v1/chat/completions"; + headers["Authorization"] = "Bearer " + apiKey; + payload = {"model": model, "messages": [{"role": "system", "content": systemPrompt}, {"role": "user", "content": prompt}], "temperature": 0}; + } + else if (serviceType === "gemini") + { + reqUrl = "https://generativelanguage.googleapis.com/v1beta/models/" + model + ":generateContent?key=" + apiKey; + payload = {"contents": [{"parts": [{"text": systemPrompt + "\n\n" + prompt}]}], "generationConfig": {"temperature": 0}}; + } + else if (serviceType === "openrouter") + { + reqUrl = "https://openrouter.ai/api/v1/chat/completions"; + headers["Authorization"] = "Bearer " + apiKey; + payload = {"model": model, "messages": [{"role": "system", "content": systemPrompt}, {"role": "user", "content": prompt}], "temperature": 0}; + } + else + { + reqUrl = endpoint || "http://localhost:11434/api/generate"; + payload = {"model": model, "prompt": systemPrompt + "\n\n" + prompt, "stream": false, "options": {"temperature": 0}}; + } + fetch(reqUrl, {method: 'POST', headers: headers, body: JSON.stringify(payload)}).then( function(response) + { + if (!response.ok) + { + throw new Error("HTTP error! Status: " + response.status); + } + return response.json(); + }).then( function(data) + { + var responseText = ""; + if (serviceType === "groq" || serviceType === "openrouter") + { + responseText = data.choices && data.choices[0] && data.choices[0].message ? data.choices[0].message.content : ""; + } + else if (serviceType === "gemini") + { + responseText = data.candidates && data.candidates[0] && data.candidates[0].content && data.candidates[0].content.parts ? data.candidates[0].content.parts[0].text : ""; + } + else + { + responseText = data.response || ""; + } + completionHandler(responseText, nil); + ((___r1 = (CPRunLoop.isa.method_msgSend["currentRunLoop"] || _objj_forward)(CPRunLoop, "currentRunLoop")), ___r1 == null ? ___r1 : (___r1.isa.method_msgSend["limitDateForMode:"] || _objj_forward)(___r1, "limitDateForMode:", CPDefaultRunLoopMode)); + var ___r1; + }).catch( function(err) + { + var cpError = (CPError.isa.method_msgSend["errorWithDomain:code:userInfo:"] || _objj_forward)(CPError, "errorWithDomain:code:userInfo:", "CPLanguageModelErrorDomain", 4, (CPDictionary.isa.method_msgSend["dictionaryWithObject:forKey:"] || _objj_forward)(CPDictionary, "dictionaryWithObject:forKey:", err.message, CPLocalizedDescriptionKey)); + completionHandler(nil, cpError); + ((___r1 = (CPRunLoop.isa.method_msgSend["currentRunLoop"] || _objj_forward)(CPRunLoop, "currentRunLoop")), ___r1 == null ? ___r1 : (___r1.isa.method_msgSend["limitDateForMode:"] || _objj_forward)(___r1, "limitDateForMode:", CPDefaultRunLoopMode)); + var ___r1; + }); +} + +,["void","CPString","id","Function"]), new objj_method(sel_getUid("_executePromptStreaming:onChunkReceived:completed:"), function $CPLanguageModelSession___executePromptStreaming_onChunkReceived_completed_(self, _cmd, prompt, chunkHandler, completionHandler) +{ + var stream; + try { + stream = self._chromeSession.promptStreaming(prompt); + } + catch(err) { + var cpError = (CPError.isa.method_msgSend["errorWithDomain:code:userInfo:"] || _objj_forward)(CPError, "errorWithDomain:code:userInfo:", "CPLanguageModelErrorDomain", 3, (CPDictionary.isa.method_msgSend["dictionaryWithObject:forKey:"] || _objj_forward)(CPDictionary, "dictionaryWithObject:forKey:", err.message, CPLocalizedDescriptionKey)); + completionHandler(nil, cpError); + ((___r1 = (CPRunLoop.isa.method_msgSend["currentRunLoop"] || _objj_forward)(CPRunLoop, "currentRunLoop")), ___r1 == null ? ___r1 : (___r1.isa.method_msgSend["limitDateForMode:"] || _objj_forward)(___r1, "limitDateForMode:", CPDefaultRunLoopMode)); + return; + } + ( async function() + { + var lastChunk = ""; + try { +for await (const chunk of stream) + { + lastChunk = chunk; + if (chunkHandler) + { + chunkHandler(chunk); + } + } + if (completionHandler) + { + completionHandler(lastChunk, nil); + ((___r1 = (CPRunLoop.isa.method_msgSend["currentRunLoop"] || _objj_forward)(CPRunLoop, "currentRunLoop")), ___r1 == null ? ___r1 : (___r1.isa.method_msgSend["limitDateForMode:"] || _objj_forward)(___r1, "limitDateForMode:", CPDefaultRunLoopMode)); + } + } + catch(err) { + if (completionHandler) + { + var cpError = (CPError.isa.method_msgSend["errorWithDomain:code:userInfo:"] || _objj_forward)(CPError, "errorWithDomain:code:userInfo:", "CPLanguageModelErrorDomain", 2, (CPDictionary.isa.method_msgSend["dictionaryWithObject:forKey:"] || _objj_forward)(CPDictionary, "dictionaryWithObject:forKey:", err.message, CPLocalizedDescriptionKey)); + completionHandler(nil, cpError); + ((___r1 = (CPRunLoop.isa.method_msgSend["currentRunLoop"] || _objj_forward)(CPRunLoop, "currentRunLoop")), ___r1 == null ? ___r1 : (___r1.isa.method_msgSend["limitDateForMode:"] || _objj_forward)(___r1, "limitDateForMode:", CPDefaultRunLoopMode)); + } + } + var ___r1; + })(); + var ___r1; +} + +,["void","CPString","Function","Function"])]); +class_addMethods(meta_class, [new objj_method(sel_getUid("initialize"), function $CPLanguageModelSession__initialize(self, _cmd) +{ + if (self === (CPLanguageModelSession.isa.method_msgSend["class"] || _objj_forward)(CPLanguageModelSession, "class")) + { + var bundle = (CPBundle.isa.method_msgSend["mainBundle"] || _objj_forward)(CPBundle, "mainBundle"); + CPLanguageModelSessionEndorsesFallback = !!(bundle == null ? bundle : (bundle.isa.method_msgSend["objectForInfoDictionaryKey:"] || _objj_forward)(bundle, "objectForInfoDictionaryKey:", "CPEndorseLanguageModelFallback")); + CPLanguageModelSessionFallbackServiceType = (bundle == null ? bundle : (bundle.isa.method_msgSend["objectForInfoDictionaryKey:"] || _objj_forward)(bundle, "objectForInfoDictionaryKey:", "CPDefaultLanguageModelService")) || "ollama"; + CPLanguageModelSessionFallbackEndpoint = (bundle == null ? bundle : (bundle.isa.method_msgSend["objectForInfoDictionaryKey:"] || _objj_forward)(bundle, "objectForInfoDictionaryKey:", "CPDefaultLanguageModelEndpoint")) || "http://localhost:11434/api/generate"; + CPLanguageModelSessionFallbackModel = (bundle == null ? bundle : (bundle.isa.method_msgSend["objectForInfoDictionaryKey:"] || _objj_forward)(bundle, "objectForInfoDictionaryKey:", "CPDefaultLanguageModelModel")) || "gemma4:e4b"; + CPLanguageModelSessionFallbackAPIKey = (bundle == null ? bundle : (bundle.isa.method_msgSend["objectForInfoDictionaryKey:"] || _objj_forward)(bundle, "objectForInfoDictionaryKey:", "CPDefaultLanguageModelAPIKey")) || ""; + CPLanguageModelSessionFallbackAPIKeyUserDefaultKey = (bundle == null ? bundle : (bundle.isa.method_msgSend["objectForInfoDictionaryKey:"] || _objj_forward)(bundle, "objectForInfoDictionaryKey:", "CPDefaultLanguageModelAPIKeyUserDefaultKey")) || ""; + } +} + +,["void"]), new objj_method(sel_getUid("setEndorsesFallback:"), function $CPLanguageModelSession__setEndorsesFallback_(self, _cmd, shouldEndorse) +{ + CPLanguageModelSessionEndorsesFallback = shouldEndorse; +} + +,["void","BOOL"]), new objj_method(sel_getUid("endorsesFallback"), function $CPLanguageModelSession__endorsesFallback(self, _cmd) +{ + return CPLanguageModelSessionEndorsesFallback; +} + +,["BOOL"]), new objj_method(sel_getUid("setFallbackServiceType:endpoint:model:apiKey:"), function $CPLanguageModelSession__setFallbackServiceType_endpoint_model_apiKey_(self, _cmd, serviceType, endpoint, model, apiKey) +{ + CPLanguageModelSessionFallbackServiceType = serviceType; + CPLanguageModelSessionFallbackEndpoint = endpoint; + CPLanguageModelSessionFallbackModel = model; + CPLanguageModelSessionFallbackAPIKey = apiKey; +} + +,["void","CPString","CPString","CPString","CPString"]), new objj_method(sel_getUid("setFallbackAPIKeyUserDefaultKey:"), function $CPLanguageModelSession__setFallbackAPIKeyUserDefaultKey_(self, _cmd, keyName) +{ + CPLanguageModelSessionFallbackAPIKeyUserDefaultKey = keyName; +} + +,["void","CPString"]), new objj_method(sel_getUid("fallbackAPIKeyUserDefaultKey"), function $CPLanguageModelSession__fallbackAPIKeyUserDefaultKey(self, _cmd) +{ + return CPLanguageModelSessionFallbackAPIKeyUserDefaultKey; +} + +,["CPString"]), new objj_method(sel_getUid("_getChromeFactoryWithCompletionHandler:"), function $CPLanguageModelSession___getChromeFactoryWithCompletionHandler_(self, _cmd, completionHandler) +{ + if (typeof window === "undefined") + { + var cpError = (CPError.isa.method_msgSend["errorWithDomain:code:userInfo:"] || _objj_forward)(CPError, "errorWithDomain:code:userInfo:", "CPLanguageModelErrorDomain", -1, (CPDictionary.isa.method_msgSend["dictionaryWithObject:forKey:"] || _objj_forward)(CPDictionary, "dictionaryWithObject:forKey:", "Execution environment is not a browser window.", CPLocalizedDescriptionKey)); + completionHandler(nil, cpError); + return; + } + if (window.ai && window.ai.languageModel) + completionHandler(window.ai.languageModel, nil); + else if (window.LanguageModel) + completionHandler(window.LanguageModel, nil); + else + completionHandler(nil, (CPError.isa.method_msgSend["errorWithDomain:code:userInfo:"] || _objj_forward)(CPError, "errorWithDomain:code:userInfo:", "CPLanguageModelErrorDomain", 0, nil)); +} + +,["void","Function"])]); +} p;10;CPLocale.jt;9223;@STATIC;1.0;i;10;CPObject.jt;9189;objj_executeFile("CPObject.j", YES);CPLocaleIdentifier = "CPLocaleIdentifier"; CPLocaleLanguageCode = "CPLocaleLanguageCode"; CPLocaleCountryCode = "CPLocaleCountryCode"; diff --git a/Resources/CPLanguageModelChatbot/AppController.j b/Resources/CPLanguageModelChatbot/AppController.j new file mode 100644 index 000000000..3d12ec8d3 --- /dev/null +++ b/Resources/CPLanguageModelChatbot/AppController.j @@ -0,0 +1,657 @@ +// AppController.j +// Manual test application for CPLanguageModelSession & CPSystemLanguageModel +// With custom SpeechBubbleBox drawing and editable System Prompt controls. +// + +@import +@import +@import + +// --- SUBCLASS: SPEECH BUBBLE VIEW --- +@implementation SpeechBubbleBox : CPView +{ + BOOL _isUser; + CPColor _bubbleColor; +} + +- (id)initWithFrame:(CGRect)aFrame isUser:(BOOL)isUser fillColor:(CPColor)aColor +{ + self = [super initWithFrame:aFrame]; + if (self) { + _isUser = isUser; + _bubbleColor = aColor; + [self setAutoresizingMask:CPViewWidthSizable]; + } + return self; +} + +- (void)drawRect:(CGRect)aRect +{ + var context = [[CPGraphicsContext currentContext] graphicsPort]; + var bounds = [self bounds]; + var w = CGRectGetWidth(bounds); + var h = CGRectGetHeight(bounds) - 10.0; // 10px spacing for the bottom triangle pointer + var r = 6.0; // Corner radius + var th = 10.0; // Tail height + + // --- 1. FILL PATH --- + CGContextBeginPath(context); + + // Top-left + CGContextMoveToPoint(context, r, 0); + + // Top edge + CGContextAddLineToPoint(context, w - r, 0); + CGContextAddArcToPoint(context, w, 0, w, r, r); + + // Right edge + CGContextAddLineToPoint(context, w, h - r); + CGContextAddArcToPoint(context, w, h, w - r, h, r); + + // Bottom edge with triangular tail (RHS vs LHS) + if (_isUser) { + CGContextAddLineToPoint(context, w - 21, h); + CGContextAddLineToPoint(context, w - 21, h + th); + CGContextAddLineToPoint(context, w - 35, h); + CGContextAddLineToPoint(context, r, h); + } else { + CGContextAddLineToPoint(context, 35, h); + CGContextAddLineToPoint(context, 21, h + th); + CGContextAddLineToPoint(context, 21, h); + CGContextAddLineToPoint(context, r, h); + } + + // Left edge + CGContextAddArcToPoint(context, 0, h, 0, h - r, r); + CGContextAddLineToPoint(context, 0, r); + CGContextAddArcToPoint(context, 0, 0, r, 0, r); + + CGContextClosePath(context); + + // Fill path + CGContextSetFillColor(context, _bubbleColor); + CGContextFillPath(context); + + // --- 2. OUTLINE PATH --- + CGContextBeginPath(context); + CGContextMoveToPoint(context, r, 0); + CGContextAddLineToPoint(context, w - r, 0); + CGContextAddArcToPoint(context, w, 0, w, r, r); + CGContextAddLineToPoint(context, w, h - r); + CGContextAddArcToPoint(context, w, h, w - r, h, r); + + if (_isUser) { + CGContextAddLineToPoint(context, w - 21, h); + CGContextAddLineToPoint(context, w - 21, h + th); + CGContextAddLineToPoint(context, w - 35, h); + CGContextAddLineToPoint(context, r, h); + } else { + CGContextAddLineToPoint(context, 35, h); + CGContextAddLineToPoint(context, 21, h + th); + CGContextAddLineToPoint(context, 21, h); + CGContextAddLineToPoint(context, r, h); + } + + CGContextAddArcToPoint(context, 0, h, 0, h - r, r); + CGContextAddLineToPoint(context, 0, r); + CGContextAddArcToPoint(context, 0, 0, r, 0, r); + CGContextClosePath(context); + + // Stroke outline + CGContextSetStrokeColor(context, [CPColor colorWithWhite:0.8 alpha:1.0]); + CGContextSetLineWidth(context, 1.0); + CGContextStrokePath(context); +} + +@end + + +// --- MAIN CONTROLLER --- +@implementation AppController : CPObject +{ + CPWindow _mainWindow; + CPScrollView _chatScrollView; + CPView _chatDocumentView; + CPTextField _chatInputField; + CPButton _chatSendButton; + CPButton _settingsButton; + CPCheckBox _forceFallbackCheckbox; + CPTextField _statusLabel; + CPTextView _systemPromptTextView; + + CPWindow _settingsWindow; + CPPopUpButton _servicePopUp; + CPTextField _endpointField; + CPTextField _modelField; + CPTextField _apiKeyField; + + CPLanguageModelSession _session; + float _currentChatY; + id _currentStreamingTextView; + CPProgressIndicator _currentSpinner; +} + +- (void)applicationDidFinishLaunching:(CPNotification)aNotification +{ + // Initialize default test settings in local user defaults + var defaults = [CPUserDefaults standardUserDefaults]; + var defaultSettings = [CPDictionary dictionaryWithObjects:[ + @"ollama", + @"http://localhost:11434/api/generate", + @"gemma4:e4b", + @"" + ] forKeys:[ + @"LLMTestServiceType", + @"LLMTestEndpoint", + @"LLMTestModel", + @"LLMTestAPIKey" + ]]; + [defaults registerDefaults:defaultSettings]; + + // Read values to apply fallback routing to CPLanguageModelSession + var activeService = [defaults objectForKey:@"LLMTestServiceType"], + endpoint = [defaults objectForKey:@"LLMTestEndpoint"], + model = [defaults objectForKey:@"LLMTestModel"], + apiKey = [defaults objectForKey:@"LLMTestAPIKey"]; + + [CPLanguageModelSession setFallbackServiceType:activeService + endpoint:endpoint + model:model + apiKey:apiKey]; + + // Main manual test window setup + _mainWindow = [[CPWindow alloc] initWithContentRect:CGRectMake(0, 0, 800, 650) + styleMask:CPTitledWindowMask | CPClosableWindowMask | CPMiniaturizableWindowMask | CPResizableWindowMask]; + [_mainWindow setTitle:@"CPLanguageModel Manual Test Tool"]; + [_mainWindow center]; + + var contentView = [_mainWindow contentView]; + var bounds = [contentView bounds]; + + // --- TOP CONTROL PANEL (Height 135px) --- + var topBar = [[CPView alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(bounds), 135)]; + [topBar setAutoresizingMask:CPViewWidthSizable | CPViewMaxYMargin]; + [topBar setBackgroundColor:[CPColor colorWithWhite:0.92 alpha:1.0]]; + [contentView addSubview:topBar]; + + _statusLabel = [[CPTextField alloc] initWithFrame:CGRectMake(15, 12, 300, 20)]; + [_statusLabel setStringValue:@"Checking capability..."]; + [_statusLabel setFont:[CPFont systemFontOfSize:12.0]]; + [topBar addSubview:_statusLabel]; + + _forceFallbackCheckbox = [[CPCheckBox alloc] initWithFrame:CGRectMake(330, 12, 140, 20)]; + [_forceFallbackCheckbox setTitle:@"Force Fallback"]; + [_forceFallbackCheckbox setTarget:self]; + [_forceFallbackCheckbox setAction:@selector(toggleForceFallback:)]; + [topBar addSubview:_forceFallbackCheckbox]; + + _settingsButton = [[CPButton alloc] initWithFrame:CGRectMake(CGRectGetWidth(bounds) - 210, 9, 90, 26)]; + [_settingsButton setTitle:@"Settings..."]; + [_settingsButton setAutoresizingMask:CPViewMinXMargin]; + [_settingsButton setTarget:self]; + [_settingsButton setAction:@selector(openSettingsSheet:)]; + [topBar addSubview:_settingsButton]; + + var clearButton = [[CPButton alloc] initWithFrame:CGRectMake(CGRectGetWidth(bounds) - 110, 9, 95, 26)]; + [clearButton setTitle:@"Clear Chat"]; + [clearButton setAutoresizingMask:CPViewMinXMargin]; + [clearButton setTarget:self]; + [clearButton setAction:@selector(clearChatAction:)]; + [topBar addSubview:clearButton]; + + // System Prompt Header & Field [1] + var promptLabel = [[CPTextField alloc] initWithFrame:CGRectMake(15, 42, 300, 18)]; + [promptLabel setStringValue:@"System Instructions (Persona):"]; + [promptLabel setFont:[CPFont boldSystemFontOfSize:11.0]]; + [promptLabel setTextColor:[CPColor darkGrayColor]]; + [topBar addSubview:promptLabel]; + + var promptScroll = [[CPScrollView alloc] initWithFrame:CGRectMake(15, 62, CGRectGetWidth(bounds) - 30, 60)]; + [promptScroll setAutoresizingMask:CPViewWidthSizable]; + [promptScroll setAutohidesScrollers:YES]; + + _systemPromptTextView = [[CPTextView alloc] initWithFrame:[promptScroll bounds]]; + [_systemPromptTextView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable]; + [_systemPromptTextView setEditable:YES]; + [_systemPromptTextView setFont:[CPFont systemFontOfSize:11.0]]; + // Default instruction preset [1] + [_systemPromptTextView setString:@"You are a helpful, concise testing assistant. You structure your explanations clearly using lists where appropriate."]; + + [promptScroll setDocumentView:_systemPromptTextView]; + [topBar addSubview:promptScroll]; + + // --- SCROLLING CHAT CONTAINER --- + var scrollHeight = CGRectGetHeight(bounds) - 195; + _chatScrollView = [[CPScrollView alloc] initWithFrame:CGRectMake(0, 135, CGRectGetWidth(bounds), scrollHeight)]; + [_chatScrollView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable]; + [_chatScrollView setAutohidesScrollers:YES]; + [_chatScrollView setHasHorizontalScroller:NO]; + [_chatScrollView setBackgroundColor:[CPColor whiteColor]]; + + _chatDocumentView = [[CPView alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth([_chatScrollView bounds]), scrollHeight)]; + [_chatDocumentView setAutoresizingMask:CPViewWidthSizable]; + [_chatScrollView setDocumentView:_chatDocumentView]; + [contentView addSubview:_chatScrollView]; + + // --- INPUT CONTAINER --- + var bottomBarY = CGRectGetHeight(bounds) - 60; + var bottomBar = [[CPView alloc] initWithFrame:CGRectMake(0, bottomBarY, CGRectGetWidth(bounds), 60)]; + [bottomBar setAutoresizingMask:CPViewWidthSizable | CPViewMinYMargin]; + [bottomBar setBackgroundColor:[CPColor colorWithWhite:0.95 alpha:1.0]]; + [contentView addSubview:bottomBar]; + + _chatInputField = [[CPTextField alloc] initWithFrame:CGRectMake(15, 13, CGRectGetWidth(bounds) - 130, 34)]; + [_chatInputField setAutoresizingMask:CPViewWidthSizable]; + [_chatInputField setEditable:YES]; + [_chatInputField setBezeled:YES]; + [_chatInputField setPlaceholderString:@"Type a prompt and press Enter..."]; + [_chatInputField setTarget:self]; + [_chatInputField setAction:@selector(submitPromptAction:)]; + [bottomBar addSubview:_chatInputField]; + + _chatSendButton = [[CPButton alloc] initWithFrame:CGRectMake(CGRectGetWidth(bounds) - 105, 13, 90, 34)]; + [_chatSendButton setTitle:@"Send"]; + [_chatSendButton setAutoresizingMask:CPViewMinXMargin]; + [_chatSendButton setTarget:self]; + [_chatSendButton setAction:@selector(submitPromptAction:)]; + [bottomBar addSubview:_chatSendButton]; + + [_mainWindow orderFront:self]; + + [self checkModelSupport]; + [self resetSession]; +} + +- (void)checkModelSupport +{ + var systemModel = [CPSystemLanguageModel defaultModel]; + [_statusLabel setStringValue:@"Checking capability..."]; + + [systemModel supportsLocaleWithCompletionHandler:function(supported) { + + if (supported) + [_statusLabel setStringValue:@"On-Device LLM: Supported"]; + else + [_statusLabel setStringValue:@"On-Device LLM: Not available. Using fallback."]; + }]; +} + +- (void)toggleForceFallback:(id)sender +{ + var force = [sender state] === CPOnState; + [CPLanguageModelSession setEndorsesFallback:force]; + [_statusLabel setStringValue:(force ? @"Fallback forced programmatically." : @"Prioritizing on-device model.")]; +} + +- (void)clearChatAction:(id)sender +{ + [self resetSession]; +} + +- (void)resetSession +{ + _currentChatY = 15; + _currentStreamingTextView = nil; + + if (_currentSpinner) { + [_currentSpinner stopAnimation:self]; + [_currentSpinner removeFromSuperview]; + _currentSpinner = nil; + } + + if (_session) { + [_session destroy]; + } + + // Read the custom instructions from the text field upon starting a fresh session [1] + var instructions = [_systemPromptTextView string] || @""; + _session = [[CPLanguageModelSession alloc] initWithInstructions:instructions]; + + [[_chatDocumentView subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)]; + [_chatDocumentView setFrameSize:CGSizeMake(CGRectGetWidth([_chatScrollView bounds]), CGRectGetHeight([_chatScrollView bounds]))]; + + [self appendMessage:@"Session initialized.\n\nEnter a query below to begin." isUser:NO]; +} + +- (void)appendMessage:(CPString)text isUser:(BOOL)isUser +{ + var docWidth = CGRectGetWidth([_chatScrollView bounds]) - 50; + + var spinner = nil; + var textX = 15; + + // Erstelle den Spinner, falls die Generierung beginnt + if (!isUser && [text isEqualToString:@"Generating response..."]) { + spinner = [[CPProgressIndicator alloc] initWithFrame:CGRectMake(15, 12, 16, 16)]; + [spinner setStyle:CPProgressIndicatorSpinningStyle]; + [spinner setControlSize:CPSmallControlSize]; + [spinner setIndeterminate:YES]; + [spinner startAnimation:self]; + _currentSpinner = spinner; + textX = 38; // Verschiebe den Text nach rechts, um Platz für den Spinner zu schaffen + } + + var textView = [[CPTextView alloc] initWithFrame:CGRectMake(textX, 10, docWidth - 15 - textX, 20)]; + [textView setEditable:YES]; + [textView setRichText:YES]; + [textView setSelectable:YES]; + [textView setBackgroundColor:[CPColor clearColor]]; + [textView setAutoresizingMask:CPViewWidthSizable]; + + [textView setVerticallyResizable:YES]; + [textView setHorizontallyResizable:NO]; + [[textView textContainer] setWidthTracksTextView:YES]; + + var textHeight = 20; + var layoutManager = [textView layoutManager]; + var textContainer = [textView textContainer]; + + try { + var parsedAttrStr = [CPMarkdownParser attributedStringFromMarkdown:text]; + [textView insertText:parsedAttrStr]; + + var usedRect = [layoutManager usedRectForTextContainer:textContainer]; + textHeight = CGRectGetHeight(usedRect); + + if (textHeight < 20) { + textHeight = 20; + } + } + catch (e) + { + // Fallback bei Parsing-Fehler + console.error("Markdown append failure: ", e); + [textView setString:text]; + [textView sizeToFit]; + textHeight = CGRectGetHeight([textView frame]); + } + + var cardHeight = textHeight + 20; + var bubbleHeight = cardHeight + 10; + + var fillColor = isUser ? [CPColor colorWithRed:0.90 green:0.93 blue:1.0 alpha:1.0] : [CPColor colorWithWhite:0.96 alpha:1.0]; + var cardBox = [[SpeechBubbleBox alloc] initWithFrame:CGRectMake(15, _currentChatY, docWidth, bubbleHeight) + isUser:isUser + fillColor:fillColor]; + + if (spinner) { + [cardBox addSubview:spinner]; + } + + [cardBox addSubview:textView]; + [_chatDocumentView addSubview:cardBox]; + + if (!isUser) { + _currentStreamingTextView = textView; + } + + _currentChatY += bubbleHeight + 15; + [_chatDocumentView setFrameSize:CGSizeMake(CGRectGetWidth([_chatScrollView bounds]), _currentChatY + 20)]; + + var boundsHeight = CGRectGetHeight([_chatScrollView bounds]); + + if (_currentChatY > boundsHeight) { + [[_chatScrollView contentView] scrollToPoint:CGPointMake(0, _currentChatY - boundsHeight + 40)]; + } +} + +- (void)updateMessage:(CPString)newText +{ + if (!_currentStreamingTextView) + return; + + // Falls ein aktiver Spinner läuft, stoppe und entferne ihn, und richte das Textfeld wieder links aus + if (_currentSpinner) { + [_currentSpinner stopAnimation:self]; + [_currentSpinner removeFromSuperview]; + _currentSpinner = nil; + + var docWidth = CGRectGetWidth([_chatScrollView bounds]) - 50; + [_currentStreamingTextView setFrame:CGRectMake(15, 10, docWidth - 30, CGRectGetHeight([_currentStreamingTextView frame]))]; + } + + try { + // 1. Text über Standard-Zuweisung neu setzen + var parsedAttrStr = [CPMarkdownParser attributedStringFromMarkdown:newText]; + + [_currentStreamingTextView setEditable:YES]; + [_currentStreamingTextView setString:@""]; + [_currentStreamingTextView insertText:parsedAttrStr]; + [_currentStreamingTextView setEditable:NO]; + + var layoutManager = [_currentStreamingTextView layoutManager]; + var textContainer = [_currentStreamingTextView textContainer]; + + var usedRect = [layoutManager usedRectForTextContainer:textContainer]; + var textHeight = CGRectGetHeight(usedRect); + + if (textHeight < 20) + textHeight = 20; + + var cardHeight = textHeight + 20; + var bubbleHeight = cardHeight + 10; + + var container = [_currentStreamingTextView superview]; + + if (container) + { + var oldBubbleHeight = CGRectGetHeight([container frame]); + + [container setFrameSize:CGSizeMake(CGRectGetWidth([container frame]), bubbleHeight)]; + [_currentStreamingTextView setFrameSize:CGSizeMake(CGRectGetWidth([_currentStreamingTextView frame]), textHeight)]; + [container setNeedsDisplay:YES]; + [_currentStreamingTextView setNeedsDisplay:YES]; + + var diffHeight = bubbleHeight - oldBubbleHeight; + _currentChatY += diffHeight; + } + + } + catch (e) + { + console.error("Markdown rendering failure: ", e); + + [_currentStreamingTextView setEditable:YES]; + [_currentStreamingTextView setString:newText]; + [_currentStreamingTextView setEditable:NO]; + + [_currentStreamingTextView sizeToFit]; + var textHeight = CGRectGetHeight([_currentStreamingTextView frame]); + + var container = [_currentStreamingTextView superview]; + + if (container) { + var oldBubbleHeight = CGRectGetHeight([container frame]); + var bubbleHeight = textHeight + 30; + [container setFrameSize:CGSizeMake(CGRectGetWidth([container frame]), bubbleHeight)]; + [container setNeedsDisplay:YES]; + + var diffHeight = bubbleHeight - oldBubbleHeight; + _currentChatY += diffHeight; + } + } + + [_chatDocumentView setFrameSize:CGSizeMake(CGRectGetWidth([_chatScrollView bounds]), _currentChatY + 20)]; + + var boundsHeight = CGRectGetHeight([_chatScrollView bounds]); + + if (_currentChatY > boundsHeight) + [[_chatScrollView contentView] scrollToPoint:CGPointMake(0, _currentChatY - boundsHeight + 40)]; +} + +- (void)submitPromptAction:(id)sender +{ + var prompt = [_chatInputField stringValue]; + + if (!prompt || [prompt stringByTrimmingWhitespace] === @"") + return; + + [_chatInputField setStringValue:@""]; + [_chatInputField setEnabled:NO]; + [_chatSendButton setEnabled:NO]; + + [self appendMessage:prompt isUser:YES]; + [self appendMessage:@"Generating response..." isUser:NO]; + + [_session respondToPrompt:prompt + options:nil + completionHandler:function(finalText, error) { + [_chatInputField setEnabled:YES]; + [_chatInputField becomeFirstResponder]; + [_chatSendButton setEnabled:YES]; + + if (error) + [self updateMessage:@"Error: " + [error localizedDescription]]; + else + [self updateMessage:finalText]; + }]; +} + +// --- CONFIGURATION POPUP SHEETS --- + +- (void)openSettingsSheet:(id)sender +{ + if (!_settingsWindow) + { + _settingsWindow = [[CPWindow alloc] initWithContentRect:CGRectMake(0, 0, 420, 260) + styleMask:CPTitledWindowMask | CPClosableWindowMask]; + [_settingsWindow setTitle:@"Fallback Settings"]; + + var sheetContentView = [_settingsWindow contentView]; + var sheetBounds = [sheetContentView bounds]; + + var serviceLabel = [[CPTextField alloc] initWithFrame:CGRectMake(15, 25, 110, 20)]; + [serviceLabel setStringValue:@"Service Type:"]; + [serviceLabel setFont:[CPFont systemFontOfSize:12.0]]; + [serviceLabel setAlignment:CPRightTextAlignment]; + [sheetContentView addSubview:serviceLabel]; + + _servicePopUp = [[CPPopUpButton alloc] initWithFrame:CGRectMake(135, 22, 180, 26) pullsDown:NO]; + [_servicePopUp addItemWithTitle:@"Ollama (Local)"]; + [[_servicePopUp lastItem] setRepresentedObject:@"ollama"]; + [_servicePopUp addItemWithTitle:@"Groq API"]; + [[_servicePopUp lastItem] setRepresentedObject:@"groq"]; + [_servicePopUp addItemWithTitle:@"Google Gemini"]; + [[_servicePopUp lastItem] setRepresentedObject:@"gemini"]; + [_servicePopUp addItemWithTitle:@"OpenRouter"]; + [[_servicePopUp lastItem] setRepresentedObject:@"openrouter"]; + [_servicePopUp setTarget:self]; + [_servicePopUp setAction:@selector(serviceTypeDidChange:)]; + [sheetContentView addSubview:_servicePopUp]; + + var endpointLabel = [[CPTextField alloc] initWithFrame:CGRectMake(15, 67, 110, 20)]; + [endpointLabel setStringValue:@"Endpoint URL:"]; + [endpointLabel setAlignment:CPRightTextAlignment]; + [sheetContentView addSubview:endpointLabel]; + + _endpointField = [[CPTextField alloc] initWithFrame:CGRectMake(135, 62, CGRectGetWidth(sheetBounds) - 155, 27)]; + [_endpointField setEditable:YES]; + [_endpointField setBezeled:YES]; + [sheetContentView addSubview:_endpointField]; + + var modelLabel = [[CPTextField alloc] initWithFrame:CGRectMake(15, 107, 110, 20)]; + [modelLabel setStringValue:@"Model Name:"]; + [modelLabel setAlignment:CPRightTextAlignment]; + [sheetContentView addSubview:modelLabel]; + + _modelField = [[CPTextField alloc] initWithFrame:CGRectMake(135, 102, CGRectGetWidth(sheetBounds) - 155, 27)]; + [_modelField setEditable:YES]; + [_modelField setBezeled:YES]; + [sheetContentView addSubview:_modelField]; + + var apiKeyLabel = [[CPTextField alloc] initWithFrame:CGRectMake(15, 147, 110, 20)]; + [apiKeyLabel setStringValue:@"API Key:"]; + [apiKeyLabel setAlignment:CPRightTextAlignment]; + [sheetContentView addSubview:apiKeyLabel]; + + _apiKeyField = [[CPTextField alloc] initWithFrame:CGRectMake(135, 142, CGRectGetWidth(sheetBounds) - 155, 27)]; + [_apiKeyField setEditable:YES]; + [_apiKeyField setBezeled:YES]; + [_apiKeyField setSecure:YES]; + [sheetContentView addSubview:_apiKeyField]; + + var btnY = CGRectGetHeight(sheetBounds) - 45; + + var cancelBtn = [[CPButton alloc] initWithFrame:CGRectMake(CGRectGetWidth(sheetBounds) - 205, btnY, 90, 26)]; + [cancelBtn setTitle:@"Cancel"]; + [cancelBtn setTarget:self]; + [cancelBtn setAction:@selector(closeSettingsSheet:)]; + [sheetContentView addSubview:cancelBtn]; + + var saveBtn = [[CPButton alloc] initWithFrame:CGRectMake(CGRectGetWidth(sheetBounds) - 105, btnY, 90, 26)]; + [saveBtn setTitle:@"Save"]; + [saveBtn setTarget:self]; + [saveBtn setAction:@selector(saveSettings:)]; + [sheetContentView addSubview:saveBtn]; + } + + var defaults = [CPUserDefaults standardUserDefaults]; + var activeService = [defaults objectForKey:@"LLMTestServiceType"] || @"ollama"; + + if (activeService === @"ollama") [_servicePopUp selectItemAtIndex:0]; + else if (activeService === @"groq") [_servicePopUp selectItemAtIndex:1]; + else if (activeService === @"gemini") [_servicePopUp selectItemAtIndex:2]; + else if (activeService === @"openrouter") [_servicePopUp selectItemAtIndex:3]; + + [_endpointField setStringValue:[defaults objectForKey:@"LLMTestEndpoint"] || @"http://localhost:11434/api/generate"]; + [_modelField setStringValue:[defaults objectForKey:@"LLMTestModel"] || @"gemma4:e4b"]; + [_apiKeyField setStringValue:[defaults objectForKey:@"LLMTestAPIKey"] || @""]; + + [self updateFieldsForService:activeService]; + + [CPApp beginSheet:_settingsWindow + modalForWindow:_mainWindow + modalDelegate:self + didEndSelector:nil + contextInfo:nil]; +} + +- (void)updateFieldsForService:(CPString)serviceType +{ + if (serviceType === @"ollama") { + [_endpointField setEnabled:YES]; + [_apiKeyField setEnabled:NO]; + [_apiKeyField setPlaceholderString:@"Not required"]; + } else { + [_endpointField setEnabled:NO]; + [_endpointField setPlaceholderString:@"Default platform endpoint used"]; + [_apiKeyField setEnabled:YES]; + [_apiKeyField setPlaceholderString:@"API Token values"]; + } +} + +- (void)serviceTypeDidChange:(id)sender +{ + var newService = [[_servicePopUp selectedItem] representedObject]; + [self updateFieldsForService:newService]; +} + +- (void)closeSettingsSheet:(id)sender +{ + [CPApp endSheet:_settingsWindow]; + [_settingsWindow orderOut:self]; +} + +- (void)saveSettings:(id)sender +{ + var defaults = [CPUserDefaults standardUserDefaults]; + var activeService = [[_servicePopUp selectedItem] representedObject] || @"ollama"; + var endpoint = [_endpointField stringValue]; + var model = [_modelField stringValue]; + var apiKey = [_apiKeyField stringValue]; + + [defaults setObject:activeService forKey:@"LLMTestServiceType"]; + [defaults setObject:endpoint forKey:@"LLMTestEndpoint"]; + [defaults setObject:model forKey:@"LLMTestModel"]; + [defaults setObject:apiKey forKey:@"LLMTestAPIKey"]; + + [CPLanguageModelSession setFallbackServiceType:activeService + endpoint:endpoint + model:model + apiKey:apiKey]; + + [self closeSettingsSheet:sender]; + [_statusLabel setStringValue:@"Fallback settings updated."]; +} + +@end diff --git a/Resources/CPLanguageModelChatbot/Info.plist b/Resources/CPLanguageModelChatbot/Info.plist new file mode 100644 index 000000000..ca0ffdd38 --- /dev/null +++ b/Resources/CPLanguageModelChatbot/Info.plist @@ -0,0 +1,12 @@ + + + + + CPApplicationDelegateClass + AppController + CPBundleName + CPLanguageModelChatbot + CPPrincipalClass + CPApplication + + diff --git a/Resources/CPLanguageModelChatbot/Jakefile b/Resources/CPLanguageModelChatbot/Jakefile new file mode 100644 index 000000000..bd57b7a0d --- /dev/null +++ b/Resources/CPLanguageModelChatbot/Jakefile @@ -0,0 +1,94 @@ +/* + * Jakefile + * CPLevelIndicator + * + * Created by Alexander Ljungberg on May 28, 2011. + * Copyright 2011, WireLoad All rights reserved. + */ + +var ENV = require("system").env, + FILE = require("file"), + JAKE = require("jake"), + task = JAKE.task, + FileList = JAKE.FileList, + app = require("cappuccino/jake").app, + configuration = ENV["CONFIG"] || ENV["CONFIGURATION"] || ENV["c"] || "Debug", + OS = require("os"); + +app ("CPLevelIndicator", function(task) +{ + task.setBuildIntermediatesPath(FILE.join("Build", "CPLevelIndicator.build", configuration)); + task.setBuildPath(FILE.join("Build", configuration)); + + task.setProductName("CPLevelIndicator"); + task.setIdentifier("com.yourcompany.CPLevelIndicator"); + task.setVersion("1.0"); + task.setAuthor("WireLoad"); + task.setEmail("feedback @nospam@ yourcompany.com"); + task.setSummary("CPLevelIndicator"); + task.setSources((new FileList("**/*.j")).exclude(FILE.join("Build", "**"))); + task.setResources(new FileList("Resources/**")); + task.setIndexFilePath("index.html"); + task.setInfoPlistPath("Info.plist"); + task.setNib2CibFlags("-R Resources/"); + + if (configuration === "Debug") + task.setCompilerFlags("-DDEBUG -g"); + else + task.setCompilerFlags("-O"); +}); + +task ("default", ["CPLevelIndicator"], function() +{ + printResults(configuration); +}); + +task ("build", ["default"]); + +task ("debug", function() +{ + ENV["CONFIGURATION"] = "Debug"; + JAKE.subjake(["."], "build", ENV); +}); + +task ("release", function() +{ + ENV["CONFIGURATION"] = "Release"; + JAKE.subjake(["."], "build", ENV); +}); + +task ("run", ["debug"], function() +{ + OS.system(["open", FILE.join("Build", "Debug", "CPLevelIndicator", "index.html")]); +}); + +task ("run-release", ["release"], function() +{ + OS.system(["open", FILE.join("Build", "Release", "CPLevelIndicator", "index.html")]); +}); + +task ("deploy", ["release"], function() +{ + FILE.mkdirs(FILE.join("Build", "Deployment", "CPLevelIndicator")); + OS.system(["press", "-f", FILE.join("Build", "Release", "CPLevelIndicator"), FILE.join("Build", "Deployment", "CPLevelIndicator")]); + printResults("Deployment") +}); + +task ("desktop", ["release"], function() +{ + FILE.mkdirs(FILE.join("Build", "Desktop", "CPLevelIndicator")); + require("cappuccino/nativehost").buildNativeHost(FILE.join("Build", "Release", "CPLevelIndicator"), FILE.join("Build", "Desktop", "CPLevelIndicator", "CPLevelIndicator.app")); + printResults("Desktop") +}); + +task ("run-desktop", ["desktop"], function() +{ + OS.system([FILE.join("Build", "Desktop", "CPLevelIndicator", "CPLevelIndicator.app", "Contents", "MacOS", "NativeHost"), "-i"]); +}); + +function printResults(configuration) +{ + print("----------------------------"); + print(configuration+" app built at path: "+FILE.join("Build", configuration, "CPLevelIndicator")); + print("----------------------------"); +} diff --git a/Resources/CPLanguageModelChatbot/Resources/spinner.gif b/Resources/CPLanguageModelChatbot/Resources/spinner.gif new file mode 100644 index 0000000000000000000000000000000000000000..a5e705f6cbdf914e5e714c35a8dfef807f19e3c2 GIT binary patch literal 1434 zcmZvbdrVVj7{t$-UNOu86#VHu^|s&3rWfwHBbPG_8{SrlB{Tv1uvvj4t6zP!)#d!Ogc zP^62J^$0+~?-ZcXXpBaq%jFsw8L`=H2?+@R02Yg-*Xw;gACBV^i3CMahr>Z667S!? zk3LDe>VLEsU;sWo$Py~o!gWuaIAnaG3Sv``&tvc+8DJO!| zt4fcbQ8tW}a&xZfgtQ9BnFYLvGG|PvCNlg&uh@Q^w9Pz}+I^hCj`vu9JQADPqdkyk zR40xycD9geUgJu1e;$L`Fpa)?Wl-2&6hO@U*KrPqK(I1H=1h?2fce}6GhhP1oBZC# z1e@gt-qFa6lZrl%s1>bdxg*W)Ebt__O(4sj6(*2X@ciUClwHH#U(NRM7XAjS z+scDZ32J*PCoslsgS~#ZlCCGo`r>S6F)Ghw5wVlqHioFaw?ucD(XoLJ0j;28oPoPV z9A}dR$0SKn>uExfkl#j09o;v$BZ909R=*p{ATNq8BJW;YduX2QMOU7$a$_L5e!G^g zpbkx5G4&FZ%7m14rTN}5YB(;x7$5XOc_hf3E|Hw$TVg)P#qf~}nOn03uqsp>UG>vi zWThIoO)-1Q#@u#O;fMC#WAf@Xj70-0g9YZ;dA$HH1fW1q=9-c>>_yA0S$7M*5?}vi z)8MU`Q%P!7sEBBnd$DrKgFQ2?O%6LpdaC%F8Pn-)EC2t=j~ zoaLamla$FX!GQqWi!%s>sj-#5SJX0IF!TP=r21Z}s)k#btN0?=I7uD9C)Gb$fZ#sm zaVq7g`LwZ%PfNpN^_N-IGLHj@AV`s#4&va7_{Hw63G6BkSGXHdogTZ%QOiRb bDpZ@qYcJKM>x%b%*HX74c8MnqfHi*u-bC?g literal 0 HcmV?d00001 diff --git a/Resources/CPLanguageModelChatbot/index-debug.html b/Resources/CPLanguageModelChatbot/index-debug.html new file mode 100644 index 000000000..1097bcf1b --- /dev/null +++ b/Resources/CPLanguageModelChatbot/index-debug.html @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + + CPLevelIndicator + + + + + + + + + + + + + + +
+
+ + + +
+
+ + + diff --git a/Resources/CPLanguageModelChatbot/index.html b/Resources/CPLanguageModelChatbot/index.html new file mode 100644 index 000000000..5c5e3bc24 --- /dev/null +++ b/Resources/CPLanguageModelChatbot/index.html @@ -0,0 +1,167 @@ + + + + + + + + + + + + + + + + + + __project.name__ + + + + + + + + + + + + +
+
+
+ +
+
+ +
+ + diff --git a/Resources/CPLanguageModelChatbot/main.j b/Resources/CPLanguageModelChatbot/main.j new file mode 100644 index 000000000..7a956f1f5 --- /dev/null +++ b/Resources/CPLanguageModelChatbot/main.j @@ -0,0 +1,18 @@ +/* + * AppController.j + * CPLevelIndicator + * + * Created by Alexander Ljungberg on May 28, 2011. + * Copyright 2011, WireLoad All rights reserved. + */ + +@import +@import + +@import "AppController.j" + + +function main(args, namedArgs) +{ + CPApplicationMain(args, namedArgs); +} diff --git a/Resources/recipes.txt b/Resources/recipes.txt index 2e2be8b02..4ba341241 100644 --- a/Resources/recipes.txt +++ b/Resources/recipes.txt @@ -1,147 +1,148 @@ -1787770110771|ArrayController1| -1787770110784|ArrayControllerInitialSelectionTest| -1787770110796|ArrayControllerRemovingFirstTest| -1787770110808|AttachedSheet| -1787770110821|AttachedSheet2| -1787770110833|Bindings| -1787770110846|CGCanvasContext| -1787770110858|CGPath| -1787770110870|CPAlertTest| -1787770110883|CPAnimatablePropertyContainerTest| -1787770110895|CPAnimationContextTest| -1787770110907|CPAnimationTest| -1787770110920|CPBinder-echo-bug| -1787770110932|CPBoxCibTest| -1787770110944|CPBoxTest| -1787770110957|CPBrowserTest| -1787770110969|CPButtonBarTest| -1787770110982|CPButtonKeyEquivalentDefaultTest| -1787770110994|CPButtonTest| -1787770111007|CPByteCountFormatter| -1787770111019|CPCollectionViewNibTest| -1787770111032|CPColor-CPImage-description| -1787770111044|CPColorWellBindings| -1787770111056|CPComboBoxTest| -1787770111069|CPControlPerformClickExceptionTest| -1787770111082|CPControlSize| -1787770111094|CPCursor| -1787770111106|CPDateFormatterTest| -1787770111119|CPDatePickerTest| -1787770111131|CPDictionaryControllerTest| -1787770111144|CPDocumentControllerTest| -1787770111156|CPFormatterTest| -1787770111169|CPGraphicsTest| -1787770111181|CPImageAndTextViewImageScaling| -1787770111193|CPImageViewAlignmentScaling| -1787770111206|CPImageViewTest| -1787770111218|CPImageViewbindingsTest| -1787770111230|CPLevelIndicator| -1787770111243|CPLocalizationTest| -1787770111255|CPLogTest| -1787770111267|CPMarkdownParser| -1787770111280|CPMenuCALayerTest| -1787770111292|CPMenuEnabledBindingsTest| -1787770111304|CPMenuKeyEquivalents| -1787770111317|CPMenuRemoveAllTest| -1787770111329|CPMenuSubmenuPlacementConstraints| -1787770111341|CPMenuTest| -1787770111354|CPOutlineViewCibTest| -1787770111366|CPOutlineViewTest| -1787770111378|CPOutlineViewViewBasedCibTest| -1787770111391|CPPanelTest| -1787770111403|CPPlatformWindow| -1787770111415|CPPlattformWindowMinSize| -1787770111428|CPPopUpButtonBindings| -1787770111440|CPPopUpButtonTest| -1787770111452|CPPopover| -1787770111465|CPPredicateEditorCibTest| -1787770111478|CPProgressIndicator| -1787770111490|CPPropertyListSerializationTest| -1787770111502|CPRadioBindings| -1787770111515|CPRuleEditorCibTest| -1787770111527|CPRuleEditorTestI8N| -1787770111540|CPScrollView| -1787770111552|CPScrollView2| -1787770111564|CPSearchField| -1787770111577|CPSearchFieldPredicateBinding| -1787770111589|CPSegmentedControlBindings| -1787770111601|CPSegmentedControlTest| -1787770111614|CPSoundTest| -1787770111626|CPSplitViewDivider| -1787770111638|CPSplitViewTest| -1787770111651|CPStackViewTest| -1787770111663|CPStepperBindings| -1787770111675|CPStepperNibTest| -1787770111688|CPTabView2| -1787770111700|CPTabViewBindings| -1787770111713|CPTabViewNib| -1787770111725|CPTableViewGroupRows| -1787770111738|CPTextField| -1787770111750|CPTextFieldEditingStyleTest| -1787770111763|CPTextFieldHeightTest| -1787770111775|CPTextFieldMovementsTest| -1787770111788|CPTextFieldMultiline| -1787770111800|CPTextView| -1787770111812|CPTextViewCibTest| -1787770111825|CPTextViewDelegateAndNotifications| -1787770111837|CPTimeZone| -1787770111850|CPTokenFieldTest| -1787770111862|CPToolTip| -1787770111874|CPToolbarTest| -1787770111886|CPTreeControllerTest| -1787770111899|CPURLConnectionAsyncTest| -1787770111911|CPURLConnectionSynchronousTest| -1787770111923|CPUserDefaults| -1787770111936|CPUserDefaultsControllerTest| -1787770111948|CPUserNotificationTest| -1787770111961|CPViewController| -1787770111973|CPVisualEffectViewTest| -1787770111986|CPWebViewTest| -1787770111998|CPWebViewTest2| -1787770112010|CPWindowLiveResizeTest| -1787770112023|CPWindowMovableTest| -1787770112035|CPWindowResizeStyle| -1787770112048|ChildWindows| -1787770112060|CompilationTests| -1787770112073|ContinuouslyUpdatesValueBinding| -1787770112085|CopyAndPaste| -1787770112097|CrossOriginTest| -1787770112110|FF4096Test| -1787770112122|FontEnhancementTest| -1787770112135|FontMetricsExplorer| -1787770112147|KeyEquivalents| -1787770112160|KeyViewLoopTest| -1787770112172|KeyWindowInTheBackgroundActivation| -1787770112184|LayoutTest| -1787770112197|LoadTimeTest| -1787770112209|LongBindings| -1787770112222|MobileTest| -1787770112234|MultipleValueBindings| -1787770112246|NSBoxTest| -1787770112259|NSBrowserTest| -1787770112271|NewTextFieldBezel| -1787770112284|Nib2CibAlignment| -1787770112296|Nib2CibBaselineAlignementTest| -1787770112308|Nib2CibSubviewsOrderTest| -1787770112320|NibAppRemixed| -1787770112333|PatternFillTest| -1787770112346|PlatformWindows| -1787770112358|PopUpButtonEscTest| -1787770112371|ScalingTest| -1787770112383|ScalingTest2| -1787770112396|ScrollviewTheming| -1787770112408|SheetWindowOrderFrontIssue| -1787770112421|SimpleBindings2| -1787770112433|SmartFoldersDemo| -1787770112445|TableTest| -1787770112458|ThemeBrowser| -1787770112470|ThemeKitchenSink| -1787770112483|TrackingArea| -1787770112495|UndoRedoWithMenuUpdate| -1787770112507|UserlandNSTest| -1787770112520|layoutEphemeralSubviewTest| -1787770112533|loadDynamicFrameworks| -1787770112545|performKeyEquivalentTest| -1787770112557|predicateWithFormat| -1787770112570|resignFirstResponder-CPControlTextDidEndEditing| -1787770112582|sizeToFitFix| +1787770188776|ArrayController1| +1787770188789|ArrayControllerInitialSelectionTest| +1787770188801|ArrayControllerRemovingFirstTest| +1787770188813|AttachedSheet| +1787770188825|AttachedSheet2| +1787770188837|Bindings| +1787770188849|CGCanvasContext| +1787770188861|CGPath| +1787770188873|CPAlertTest| +1787770188885|CPAnimatablePropertyContainerTest| +1787770188898|CPAnimationContextTest| +1787770188910|CPAnimationTest| +1787770188922|CPBinder-echo-bug| +1787770188934|CPBoxCibTest| +1787770188947|CPBoxTest| +1787770188959|CPBrowserTest| +1787770188971|CPButtonBarTest| +1787770188984|CPButtonKeyEquivalentDefaultTest| +1787770188996|CPButtonTest| +1787770189008|CPByteCountFormatter| +1787770189021|CPCollectionViewNibTest| +1787770189033|CPColor-CPImage-description| +1787770189045|CPColorWellBindings| +1787770189058|CPComboBoxTest| +1787770189070|CPControlPerformClickExceptionTest| +1787770189082|CPControlSize| +1787770189094|CPCursor| +1787770189106|CPDateFormatterTest| +1787770189119|CPDatePickerTest| +1787770189131|CPDictionaryControllerTest| +1787770189143|CPDocumentControllerTest| +1787770189155|CPFormatterTest| +1787770189167|CPGraphicsTest| +1787770189180|CPImageAndTextViewImageScaling| +1787770189192|CPImageViewAlignmentScaling| +1787770189204|CPImageViewTest| +1787770189216|CPImageViewbindingsTest| +1787770189228|CPLanguageModelChatbot| +1787770189240|CPLevelIndicator| +1787770189253|CPLocalizationTest| +1787770189265|CPLogTest| +1787770189277|CPMarkdownParser| +1787770189289|CPMenuCALayerTest| +1787770189301|CPMenuEnabledBindingsTest| +1787770189314|CPMenuKeyEquivalents| +1787770189326|CPMenuRemoveAllTest| +1787770189338|CPMenuSubmenuPlacementConstraints| +1787770189350|CPMenuTest| +1787770189362|CPOutlineViewCibTest| +1787770189374|CPOutlineViewTest| +1787770189387|CPOutlineViewViewBasedCibTest| +1787770189399|CPPanelTest| +1787770189411|CPPlatformWindow| +1787770189423|CPPlattformWindowMinSize| +1787770189435|CPPopUpButtonBindings| +1787770189447|CPPopUpButtonTest| +1787770189459|CPPopover| +1787770189472|CPPredicateEditorCibTest| +1787770189484|CPProgressIndicator| +1787770189496|CPPropertyListSerializationTest| +1787770189508|CPRadioBindings| +1787770189520|CPRuleEditorCibTest| +1787770189533|CPRuleEditorTestI8N| +1787770189545|CPScrollView| +1787770189557|CPScrollView2| +1787770189569|CPSearchField| +1787770189581|CPSearchFieldPredicateBinding| +1787770189594|CPSegmentedControlBindings| +1787770189606|CPSegmentedControlTest| +1787770189618|CPSoundTest| +1787770189631|CPSplitViewDivider| +1787770189643|CPSplitViewTest| +1787770189655|CPStackViewTest| +1787770189667|CPStepperBindings| +1787770189679|CPStepperNibTest| +1787770189691|CPTabView2| +1787770189704|CPTabViewBindings| +1787770189716|CPTabViewNib| +1787770189728|CPTableViewGroupRows| +1787770189740|CPTextField| +1787770189752|CPTextFieldEditingStyleTest| +1787770189764|CPTextFieldHeightTest| +1787770189776|CPTextFieldMovementsTest| +1787770189789|CPTextFieldMultiline| +1787770189801|CPTextView| +1787770189813|CPTextViewCibTest| +1787770189825|CPTextViewDelegateAndNotifications| +1787770189837|CPTimeZone| +1787770189849|CPTokenFieldTest| +1787770189861|CPToolTip| +1787770189874|CPToolbarTest| +1787770189886|CPTreeControllerTest| +1787770189898|CPURLConnectionAsyncTest| +1787770189910|CPURLConnectionSynchronousTest| +1787770189922|CPUserDefaults| +1787770189934|CPUserDefaultsControllerTest| +1787770189947|CPUserNotificationTest| +1787770189959|CPViewController| +1787770189971|CPVisualEffectViewTest| +1787770189983|CPWebViewTest| +1787770189996|CPWebViewTest2| +1787770190008|CPWindowLiveResizeTest| +1787770190020|CPWindowMovableTest| +1787770190032|CPWindowResizeStyle| +1787770190044|ChildWindows| +1787770190056|CompilationTests| +1787770190069|ContinuouslyUpdatesValueBinding| +1787770190081|CopyAndPaste| +1787770190093|CrossOriginTest| +1787770190105|FF4096Test| +1787770190118|FontEnhancementTest| +1787770190130|FontMetricsExplorer| +1787770190142|KeyEquivalents| +1787770190155|KeyViewLoopTest| +1787770190167|KeyWindowInTheBackgroundActivation| +1787770190180|LayoutTest| +1787770190192|LoadTimeTest| +1787770190204|LongBindings| +1787770190217|MobileTest| +1787770190229|MultipleValueBindings| +1787770190241|NSBoxTest| +1787770190254|NSBrowserTest| +1787770190266|NewTextFieldBezel| +1787770190278|Nib2CibAlignment| +1787770190290|Nib2CibBaselineAlignementTest| +1787770190302|Nib2CibSubviewsOrderTest| +1787770190315|NibAppRemixed| +1787770190327|PatternFillTest| +1787770190339|PlatformWindows| +1787770190351|PopUpButtonEscTest| +1787770190363|ScalingTest| +1787770190376|ScalingTest2| +1787770190388|ScrollviewTheming| +1787770190400|SheetWindowOrderFrontIssue| +1787770190412|SimpleBindings2| +1787770190425|SmartFoldersDemo| +1787770190437|TableTest| +1787770190449|ThemeBrowser| +1787770190461|ThemeKitchenSink| +1787770190473|TrackingArea| +1787770190486|UndoRedoWithMenuUpdate| +1787770190498|UserlandNSTest| +1787770190510|layoutEphemeralSubviewTest| +1787770190522|loadDynamicFrameworks| +1787770190534|performKeyEquivalentTest| +1787770190546|predicateWithFormat| +1787770190559|resignFirstResponder-CPControlTextDidEndEditing| +1787770190571|sizeToFitFix|