mirror of
https://github.com/epistemic-technology/co-intelligence.git
synced 2026-07-22 06:45:17 +00:00
Merge pull request #12 from Epistemic-Technology/coding-style-fixes
Fix lint issues from Obsidian plugin review bot
This commit is contained in:
commit
d35ddbe8f1
24 changed files with 2688 additions and 118 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -137,3 +137,6 @@ dist
|
|||
|
||||
#macos
|
||||
.DS_Store
|
||||
|
||||
# Manual test vault
|
||||
test-vault/
|
||||
|
|
|
|||
38
eslint.config.mjs
Normal file
38
eslint.config.mjs
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
import obsidianmd from "eslint-plugin-obsidianmd";
|
||||
import tseslint from "typescript-eslint";
|
||||
|
||||
export default tseslint.config(
|
||||
{
|
||||
ignores: ["node_modules/**", "dist/**", "test/**"],
|
||||
},
|
||||
{
|
||||
files: ["src/**/*.{ts,tsx}"],
|
||||
plugins: {
|
||||
obsidianmd,
|
||||
},
|
||||
rules: {
|
||||
...obsidianmd.configs.recommended,
|
||||
},
|
||||
},
|
||||
...tseslint.configs.recommendedTypeChecked.map((config) => ({
|
||||
...config,
|
||||
files: ["src/**/*.{ts,tsx}"],
|
||||
})),
|
||||
{
|
||||
files: ["src/**/*.{ts,tsx}"],
|
||||
languageOptions: {
|
||||
parserOptions: {
|
||||
projectService: true,
|
||||
tsconfigRootDir: import.meta.dirname,
|
||||
},
|
||||
},
|
||||
rules: {
|
||||
"@typescript-eslint/no-unused-vars": "warn",
|
||||
"@typescript-eslint/no-floating-promises": "error",
|
||||
"@typescript-eslint/require-await": "error",
|
||||
"@typescript-eslint/no-misused-promises": "error",
|
||||
"@typescript-eslint/restrict-template-expressions": "error",
|
||||
"no-console": ["error", { allow: ["warn", "error", "debug"] }],
|
||||
},
|
||||
},
|
||||
);
|
||||
|
|
@ -36,10 +36,13 @@
|
|||
"@vitest/coverage-v8": "^4.0.18",
|
||||
"@vitest/ui": "^4.0.18",
|
||||
"esbuild": "^0.25.5",
|
||||
"eslint": "^9.39.2",
|
||||
"eslint-plugin-obsidianmd": "^0.1.9",
|
||||
"jsdom": "^26.1.0",
|
||||
"obsidian": "^1.8.7",
|
||||
"postcss": "^8.5.4",
|
||||
"typescript": "^5.8.3",
|
||||
"typescript-eslint": "^8.55.0",
|
||||
"vite": "^7.3.1",
|
||||
"vite-plugin-solid": "^2.11.10",
|
||||
"vite-plugin-static-copy": "^3.2.0",
|
||||
|
|
|
|||
2570
pnpm-lock.yaml
2570
pnpm-lock.yaml
File diff suppressed because it is too large
Load diff
|
|
@ -38,7 +38,7 @@ export class ChatView extends TextFileView {
|
|||
public contextItems: ContextItems = { notes: [], tags: [], sources: [] };
|
||||
public sources: Source[] = [];
|
||||
public rootElement: Element | null = null;
|
||||
public dispose: any;
|
||||
public dispose: (() => void) | null = null;
|
||||
|
||||
private updating = false;
|
||||
private debounceTimeout: number | null = null;
|
||||
|
|
@ -60,13 +60,13 @@ export class ChatView extends TextFileView {
|
|||
return this.file?.basename || "Co-Intelligence Chat";
|
||||
}
|
||||
|
||||
async debounceUpdateViewData() {
|
||||
debounceUpdateViewData() {
|
||||
if (this.debounceTimeout) {
|
||||
window.clearTimeout(this.debounceTimeout);
|
||||
}
|
||||
this.debounceTimeout = window.setTimeout(() => {
|
||||
this.debounceTimeout = null;
|
||||
this.updateViewData();
|
||||
void this.updateViewData();
|
||||
}, 500);
|
||||
}
|
||||
|
||||
|
|
@ -79,7 +79,7 @@ export class ChatView extends TextFileView {
|
|||
}
|
||||
this.updating = true;
|
||||
const currentNoteContent = await this.app.vault.cachedRead(this.file);
|
||||
const content = await serializeCoiNoteContent(
|
||||
const content = serializeCoiNoteContent(
|
||||
currentNoteContent,
|
||||
this.app,
|
||||
this.messages,
|
||||
|
|
@ -94,7 +94,7 @@ export class ChatView extends TextFileView {
|
|||
return this.data;
|
||||
}
|
||||
|
||||
async setViewData(data: string, clear: boolean) {
|
||||
setViewData(data: string, clear: boolean): void {
|
||||
this.data = data;
|
||||
if (!this.file) {
|
||||
new Notice("Error: file is null while trying to set view data");
|
||||
|
|
@ -105,7 +105,7 @@ export class ChatView extends TextFileView {
|
|||
this.clear();
|
||||
}
|
||||
const metadata = this.app.metadataCache.getFileCache(this.file);
|
||||
const { messages, contextItems, sources } = await deserializeCoiNoteContent(
|
||||
const { messages, contextItems, sources } = deserializeCoiNoteContent(
|
||||
data,
|
||||
metadata,
|
||||
this.app,
|
||||
|
|
@ -128,7 +128,7 @@ export class ChatView extends TextFileView {
|
|||
}
|
||||
}
|
||||
|
||||
async render() {
|
||||
render() {
|
||||
this.rootElement = this.rootElement || this.containerEl.children[1];
|
||||
if (!this.rootElement) {
|
||||
new Notice("Error: root element is null");
|
||||
|
|
@ -146,7 +146,7 @@ export class ChatView extends TextFileView {
|
|||
app={this.app}
|
||||
plugin={this.plugin}
|
||||
file={file}
|
||||
onChange={this.handleChatChange}
|
||||
onChange={(props) => void this.handleChatChange(props)}
|
||||
initialMessages={this.messages}
|
||||
initialContext={this.contextItems}
|
||||
initialSources={this.sources}
|
||||
|
|
@ -183,8 +183,8 @@ export class ChatView extends TextFileView {
|
|||
await renameNote(this.file, newTitle, this.app, this.plugin);
|
||||
}
|
||||
} catch (error) {
|
||||
new Notice(`Error serializing CoiNote: ${error}`);
|
||||
console.error(`Error serializing CoiNote: ${error}`);
|
||||
new Notice(`Error serializing CoiNote: ${String(error)}`);
|
||||
console.error(`Error serializing CoiNote: ${String(error)}`);
|
||||
} finally {
|
||||
this.updating = false;
|
||||
}
|
||||
|
|
@ -199,10 +199,10 @@ export class ChatView extends TextFileView {
|
|||
this.messages = messages;
|
||||
this.contextItems = contextItems;
|
||||
this.sources = sources;
|
||||
await this.render();
|
||||
this.render();
|
||||
}
|
||||
|
||||
async onUnloadFile(file: TFile): Promise<void> {
|
||||
onUnloadFile(_file: TFile): void {
|
||||
this.clear();
|
||||
}
|
||||
|
||||
|
|
@ -220,7 +220,7 @@ export class ChatView extends TextFileView {
|
|||
this.messages = messages;
|
||||
this.contextItems = contextItems;
|
||||
this.sources = sources;
|
||||
await this.render();
|
||||
this.render();
|
||||
}
|
||||
|
||||
async refresh(): Promise<void> {
|
||||
|
|
@ -228,10 +228,10 @@ export class ChatView extends TextFileView {
|
|||
await this.onOpen();
|
||||
}
|
||||
|
||||
onPaneMenu(menu: Menu, source: "more-options" | "tab-header" | string): void {
|
||||
onPaneMenu(menu: Menu, source: string): void {
|
||||
menu.addItem((item) => {
|
||||
item
|
||||
.setTitle("View as markdown")
|
||||
.setTitle("View as Markdown")
|
||||
.setIcon("bot-message-square")
|
||||
.onClick(() => {
|
||||
this.app.commands.executeCommandById(
|
||||
|
|
|
|||
|
|
@ -50,8 +50,8 @@ export class CoIntelligencePlugin extends Plugin {
|
|||
(leaf: WorkspaceLeaf) => new ChatView(leaf, this, this.app),
|
||||
);
|
||||
|
||||
this.addRibbonIcon("bot-message-square", "New COI chat", () => {
|
||||
createCOINote(this.app, this);
|
||||
this.addRibbonIcon("bot-message-square", "New chat", () => {
|
||||
void createCOINote(this.app, this);
|
||||
});
|
||||
this.registerEvent(
|
||||
this.app.workspace.on("file-open", this.handleFileOpen.bind(this)),
|
||||
|
|
@ -66,7 +66,7 @@ export class CoIntelligencePlugin extends Plugin {
|
|||
this.app.workspace.onLayoutReady(this.onloadOnLayoutReady.bind(this));
|
||||
}
|
||||
|
||||
async onloadOnLayoutReady() {
|
||||
onloadOnLayoutReady() {
|
||||
this.registerMonkeyPatches();
|
||||
}
|
||||
|
||||
|
|
@ -99,18 +99,18 @@ export class CoIntelligencePlugin extends Plugin {
|
|||
}
|
||||
}
|
||||
|
||||
private async onFileMenuHandler(
|
||||
private onFileMenuHandler(
|
||||
menu: Menu,
|
||||
file: TFile,
|
||||
source: string,
|
||||
leaf: WorkspaceLeaf,
|
||||
_source: string,
|
||||
_leaf: WorkspaceLeaf,
|
||||
) {
|
||||
if (!isCoiNote(file, this.app) || isActiveCoiNote(file, this.app)) {
|
||||
return;
|
||||
}
|
||||
menu.addItem((item) => {
|
||||
item.setTitle("View as chat");
|
||||
item.onClick(async () => {
|
||||
item.onClick(() => {
|
||||
this.app.commands.executeCommandById(
|
||||
"co-intelligence:toggle-chat-view",
|
||||
);
|
||||
|
|
@ -141,13 +141,17 @@ export class CoIntelligencePlugin extends Plugin {
|
|||
this.register(
|
||||
around(WorkspaceLeaf.prototype, {
|
||||
setViewState(next) {
|
||||
return function (this: any, state: ViewState, eState?: any) {
|
||||
return function (
|
||||
this: WorkspaceLeaf,
|
||||
state: ViewState,
|
||||
eState?: unknown,
|
||||
) {
|
||||
const newState = {
|
||||
...state,
|
||||
};
|
||||
if (state.type === "markdown") {
|
||||
const path = (state.state?.file as string) ?? "";
|
||||
if (isPathActiveCoiNote(path, this.app as App)) {
|
||||
if (isPathActiveCoiNote(path, this.app)) {
|
||||
newState.type = VIEW_TYPE_COI_CHAT;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Component, Context, createContext } from "solid-js";
|
||||
import { Component, createContext } from "solid-js";
|
||||
import { ModelChatMessage } from "@/types";
|
||||
import { App, TFile } from "obsidian";
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { App, Plugin, Command, TFile, TFolder, normalizePath } from "obsidian";
|
||||
import { App, Command } from "obsidian";
|
||||
|
||||
import CoIntelligencePlugin from "@/CoIntelligencePlugin";
|
||||
import { createCOINote } from "@/utils/notes";
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ export class ToggleChatViewCommand implements Command {
|
|||
return;
|
||||
}
|
||||
|
||||
this.performToggle(currentFile);
|
||||
void this.performToggle(currentFile);
|
||||
return;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { Component, onMount, createSignal } from "solid-js";
|
||||
import { App, TFile, Menu, setIcon } from "obsidian";
|
||||
import { Component } from "solid-js";
|
||||
import { App, TFile, Menu } from "obsidian";
|
||||
import { NoteLinkSuggestionModal } from "@/components/NoteLinkSuggestionModal";
|
||||
import { TagSuggestionModal } from "@/components/TagSuggestionModal";
|
||||
import { Tag } from "@/types";
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { ModelChatMessage } from "@/types";
|
|||
|
||||
import { ChatMessage } from "@/components/ChatMessage";
|
||||
import { MarkdownView } from "@/components/MarkdownView";
|
||||
import { AppContext, FileContext, PluginContext } from "@/CoiChatApp";
|
||||
import { FileContext } from "@/CoiChatApp";
|
||||
|
||||
export interface BotMessageProps {
|
||||
message: ModelChatMessage;
|
||||
|
|
@ -14,7 +14,7 @@ export const BotMessage: Component<BotMessageProps> = ({
|
|||
}: BotMessageProps) => {
|
||||
const file = useContext(FileContext);
|
||||
const filePath = file?.path || "";
|
||||
const content = message.content as string;
|
||||
const content = (message.content as string) || "";
|
||||
// Perplexity models use <think> tags to indicate the reasoning section.
|
||||
// OpenAI models use chunk types instead. These are translated into <think>
|
||||
// tags by handleSendMessage in ChatInterface.tsx
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ export const ChatInterface = ({
|
|||
const modelSetting = plugin.settings.defaultModel;
|
||||
let currentModel: Model | null = null;
|
||||
if (modelSetting) {
|
||||
currentModel = registry.getModel(modelSetting as ModelId);
|
||||
currentModel = registry.getModel(modelSetting);
|
||||
} else {
|
||||
currentModel = registry.getDefaultModel();
|
||||
}
|
||||
|
|
@ -164,7 +164,7 @@ export const ChatInterface = ({
|
|||
|
||||
try {
|
||||
setIsProcessing(true);
|
||||
const responseStream = await generateChatResponse(request, registry);
|
||||
const responseStream = generateChatResponse(request, registry);
|
||||
let accumulatedContent = "";
|
||||
let isFirstChunk = true;
|
||||
let chunk;
|
||||
|
|
@ -173,31 +173,37 @@ export const ChatInterface = ({
|
|||
try {
|
||||
for await (chunk of responseStream.fullStream) {
|
||||
if (chunk.type === "error") {
|
||||
console.log("Error:", chunk.error);
|
||||
console.error("Error:", chunk.error);
|
||||
new Notice("Unknown error occurred. See console log for details.");
|
||||
}
|
||||
if (chunk.type !== "text-delta" && chunk.type !== "reasoning") {
|
||||
if (
|
||||
chunk.type !== "text-delta" &&
|
||||
chunk.type !== "reasoning-delta"
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
if (!chunk.text) {
|
||||
continue;
|
||||
}
|
||||
if (isFirstChunk) {
|
||||
const assistantMessage: ModelChatMessage = {
|
||||
role: "assistant",
|
||||
content: chunk.textDelta,
|
||||
content: chunk.text,
|
||||
};
|
||||
setMessages([...messages(), assistantMessage]);
|
||||
if (chunk.type === "reasoning") {
|
||||
if (chunk.type === "reasoning-delta") {
|
||||
accumulatedContent = "<think>";
|
||||
doingReasoning = true;
|
||||
}
|
||||
accumulatedContent += chunk.textDelta;
|
||||
accumulatedContent += chunk.text;
|
||||
isFirstChunk = false;
|
||||
setIsProcessing(false);
|
||||
} else {
|
||||
if (doingReasoning && chunk.type !== "reasoning") {
|
||||
if (doingReasoning && chunk.type !== "reasoning-delta") {
|
||||
accumulatedContent += "</think>";
|
||||
doingReasoning = false;
|
||||
}
|
||||
accumulatedContent += chunk.textDelta;
|
||||
accumulatedContent += chunk.text;
|
||||
setMessages((prevMessages) => {
|
||||
const updatedMessages = [...prevMessages];
|
||||
updatedMessages[updatedMessages.length - 1] = {
|
||||
|
|
@ -365,7 +371,7 @@ export const ChatInterface = ({
|
|||
/>
|
||||
<UserInput
|
||||
triggerChange={triggerChange}
|
||||
onSubmit={handleSendMessage}
|
||||
onSubmit={(msg, ws, sp) => void handleSendMessage(msg, ws, sp)}
|
||||
currentModel={model}
|
||||
updateModel={setModel}
|
||||
onLinkNote={handleLinkNote}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Component, useContext, Accessor } from "solid-js";
|
||||
import { Component, useContext } from "solid-js";
|
||||
import { ModelChatMessage } from "@/types";
|
||||
|
||||
import { MarkdownView } from "@/components/MarkdownView";
|
||||
|
|
@ -32,7 +32,7 @@ export const ChatMessage: Component<ModelChatMessageProps> = ({
|
|||
window.open(newHref);
|
||||
} else if (anchor.classList.contains("internal-link")) {
|
||||
const newLeaf = event.ctrlKey || event.metaKey;
|
||||
app.workspace.openLinkText(href, "", newLeaf);
|
||||
void app.workspace.openLinkText(href, "", newLeaf);
|
||||
} else {
|
||||
window.open(href, "_blank");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import {
|
|||
} from "solid-js";
|
||||
import { NoteLink } from "@/components/NoteLink";
|
||||
import { AddContextMenu } from "@/components/AddContextMenu";
|
||||
import { ContextItems, Source, Tag } from "@/types";
|
||||
import { ContextItems, Tag } from "@/types";
|
||||
import { contextTokenEstimate } from "@/utils/model-context";
|
||||
|
||||
export interface ContextListProps {
|
||||
|
|
@ -82,7 +82,7 @@ export const ContextList = ({
|
|||
console.warn("Item is not a TFile");
|
||||
return;
|
||||
}
|
||||
app.workspace.openLinkText(item.basename, "");
|
||||
void app.workspace.openLinkText(item.basename, "");
|
||||
} else {
|
||||
// Simulate clicking the tag link
|
||||
window.open(
|
||||
|
|
|
|||
|
|
@ -16,16 +16,12 @@ export const MarkdownView = ({
|
|||
const app = useContext(AppContext);
|
||||
const plugin = useContext(PluginContext);
|
||||
if (!app) {
|
||||
new Notice(
|
||||
"Error: AppContext is not available while creating MarkdownView",
|
||||
);
|
||||
new Notice("Error: app context is not available");
|
||||
console.error("AppContext is not available");
|
||||
return null;
|
||||
}
|
||||
if (!plugin) {
|
||||
new Notice(
|
||||
"Error: PluginContext is not available while creating MarkdownView",
|
||||
);
|
||||
new Notice("Error: plugin context is not available");
|
||||
console.error("PluginContext is not available");
|
||||
return null;
|
||||
}
|
||||
|
|
@ -50,21 +46,21 @@ export const MarkdownView = ({
|
|||
currentRenderChild,
|
||||
);
|
||||
} catch (error) {
|
||||
new Notice("Error: failed to render markdown");
|
||||
console.error("Failed to render markdown:", error);
|
||||
containerRef.textContent = "Error rendering markdown";
|
||||
new Notice("Error: failed to render Markdown");
|
||||
console.error("Failed to render Markdown:", error);
|
||||
containerRef.textContent = "Error rendering Markdown";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
createEffect(() => {
|
||||
if (markdown) {
|
||||
renderMarkdown();
|
||||
void renderMarkdown();
|
||||
}
|
||||
});
|
||||
|
||||
onMount(() => {
|
||||
renderMarkdown();
|
||||
void renderMarkdown();
|
||||
});
|
||||
|
||||
onCleanup(() => {
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ export const NoteLink: Component<LinkProps> = (props) => {
|
|||
const app = useContext(AppContext);
|
||||
const file = useContext(FileContext);
|
||||
if (!file) {
|
||||
new Notice("Error: no file context for NoteLink");
|
||||
new Notice("Error: no file context available");
|
||||
console.error("NoteLink called with no file context");
|
||||
return null;
|
||||
}
|
||||
|
|
@ -27,7 +27,7 @@ export const NoteLink: Component<LinkProps> = (props) => {
|
|||
return;
|
||||
}
|
||||
const filePath = file?.path ?? "";
|
||||
app?.workspace.openLinkText(local.href, filePath);
|
||||
void app?.workspace.openLinkText(local.href, filePath);
|
||||
};
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Component, createEffect } from "solid-js";
|
||||
import { Component } from "solid-js";
|
||||
|
||||
export interface ProcessingIndicatorProps {
|
||||
onCancel?: () => void;
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import {
|
|||
} from "solid-js";
|
||||
import { TFile } from "obsidian";
|
||||
|
||||
import { ModelSelector, ModelSelectorProps } from "@/components/ModelSelector";
|
||||
import { ModelSelector } from "@/components/ModelSelector";
|
||||
import { SystemPromptSelector } from "@/components/SystemPromptSelector";
|
||||
import { NoteLinkSuggestionModal } from "@/components/NoteLinkSuggestionModal";
|
||||
import { TagSuggestionModal } from "@/components/TagSuggestionModal";
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Component, Accessor } from "solid-js";
|
||||
import { Component } from "solid-js";
|
||||
import { ModelChatMessage } from "@/types";
|
||||
|
||||
import { ChatMessage } from "./ChatMessage";
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { createOpenAI } from "@ai-sdk/openai";
|
|||
import { createAnthropic } from "@ai-sdk/anthropic";
|
||||
import { createGoogleGenerativeAI } from "@ai-sdk/google";
|
||||
import { createPerplexity } from "@ai-sdk/perplexity";
|
||||
import { Model, ModelId, Provider } from "@/types";
|
||||
import { Model, ModelId } from "@/types";
|
||||
import { ProviderRegistryInternal } from "@/types-extended";
|
||||
import type { CoIntelligencePlugin } from "@/CoIntelligencePlugin";
|
||||
import { Notice } from "obsidian";
|
||||
|
|
@ -233,8 +233,8 @@ export class ModelRegistry {
|
|||
}
|
||||
throw new Error("OpenAI responses method not available");
|
||||
} catch (error) {
|
||||
new Notice("Error fetching OpenAI responses model");
|
||||
console.error(`Error fetching OpenAI responses model: ${error}`);
|
||||
new Notice("Error: could not fetch responses model");
|
||||
console.error(`Error fetching OpenAI responses model: ${String(error)}`);
|
||||
//fall through to default behavior
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,10 +25,10 @@ const abortControllers = new Map<string, AbortController>();
|
|||
* @returns For stream=true: a Promise of StreamTextResult object with streaming capabilities
|
||||
* For stream=false: a Promise of GenerateTextResult object with the complete response
|
||||
*/
|
||||
export async function generateChatResponse(
|
||||
export function generateChatResponse(
|
||||
request: ChatRequest,
|
||||
registry: ModelRegistry,
|
||||
): Promise<StreamTextResult<ToolSet, never>> {
|
||||
): StreamTextResult<ToolSet, never> {
|
||||
const model = registry.getLanguageModel(request.modelId);
|
||||
|
||||
const abortController = new AbortController();
|
||||
|
|
|
|||
|
|
@ -144,11 +144,11 @@ export class CoIntelligenceSettingsTab extends PluginSettingTab {
|
|||
});
|
||||
|
||||
new Setting(containerEl)
|
||||
// eslint-disable-next-line obsidianmd/ui/sentence-case -- brand name
|
||||
.setName("OpenAI API key")
|
||||
.setDesc("Enter your OpenAI API key")
|
||||
.addText((text) => {
|
||||
text
|
||||
.setPlaceholder("Enter your OpenAI API key")
|
||||
.setPlaceholder("Enter API key")
|
||||
.setValue(this.plugin.settings.openaiApiKey)
|
||||
.onChange((value) => this.saveSetting("openaiApiKey", value));
|
||||
text.inputEl.addEventListener("blur", () =>
|
||||
|
|
@ -158,10 +158,9 @@ export class CoIntelligenceSettingsTab extends PluginSettingTab {
|
|||
|
||||
new Setting(containerEl)
|
||||
.setName("Anthropic API key")
|
||||
.setDesc("Enter your Anthropic API key")
|
||||
.addText((text) => {
|
||||
text
|
||||
.setPlaceholder("Enter your Anthropic API key")
|
||||
.setPlaceholder("Enter API key")
|
||||
.setValue(this.plugin.settings.anthropicApiKey)
|
||||
.onChange((value) => this.saveSetting("anthropicApiKey", value));
|
||||
text.inputEl.addEventListener("blur", () =>
|
||||
|
|
@ -171,10 +170,9 @@ export class CoIntelligenceSettingsTab extends PluginSettingTab {
|
|||
|
||||
new Setting(containerEl)
|
||||
.setName("Google API key")
|
||||
.setDesc("Enter your Google API key")
|
||||
.addText((text) => {
|
||||
text
|
||||
.setPlaceholder("Enter your Google API key")
|
||||
.setPlaceholder("Enter API key")
|
||||
.setValue(this.plugin.settings.googleApiKey)
|
||||
.onChange((value) => this.saveSetting("googleApiKey", value));
|
||||
text.inputEl.addEventListener("blur", () =>
|
||||
|
|
@ -184,10 +182,9 @@ export class CoIntelligenceSettingsTab extends PluginSettingTab {
|
|||
|
||||
new Setting(containerEl)
|
||||
.setName("Perplexity API key")
|
||||
.setDesc("Enter your Perplexity API key")
|
||||
.addText((text) => {
|
||||
text
|
||||
.setPlaceholder("Enter your Perplexity API key")
|
||||
.setPlaceholder("Enter API key")
|
||||
.setValue(this.plugin.settings.perplexityApiKey)
|
||||
.onChange((value) => this.saveSetting("perplexityApiKey", value));
|
||||
text.inputEl.addEventListener("blur", () =>
|
||||
|
|
@ -197,17 +194,17 @@ export class CoIntelligenceSettingsTab extends PluginSettingTab {
|
|||
|
||||
new Setting(containerEl)
|
||||
.setName("Default folder")
|
||||
.setDesc("Enter the default folder for CoIntelligence")
|
||||
.setDesc("Enter the default folder")
|
||||
.addText((text) =>
|
||||
text
|
||||
.setPlaceholder("Enter the default folder for CoIntelligence")
|
||||
.setPlaceholder("Enter the default folder")
|
||||
.setValue(this.plugin.settings.defaultFolder)
|
||||
.onChange((value) => this.saveSetting("defaultFolder", value)),
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName("Default model")
|
||||
.setDesc("Enter the default model for CoIntelligence")
|
||||
.setDesc("Enter the default model")
|
||||
.addDropdown((dropdown) => {
|
||||
this.defaultModelSelect = dropdown.selectEl;
|
||||
|
||||
|
|
@ -295,8 +292,8 @@ export class CoIntelligenceSettingsTab extends PluginSettingTab {
|
|||
href: "https://ko-fi.com/epistemictechnology",
|
||||
cls: "coi-settings-donate-link",
|
||||
});
|
||||
const srOnlySpan = kofiLink.createEl("span", {
|
||||
text: "Support me on Ko-fi",
|
||||
kofiLink.createEl("span", {
|
||||
text: "Support me on ko-fi",
|
||||
cls: "coi-sr-only",
|
||||
});
|
||||
kofiLink.createEl("img", {
|
||||
|
|
|
|||
|
|
@ -12,14 +12,7 @@ import { ModelChatMessage } from "@/types";
|
|||
import { ModelRegistry } from "@/services/model-registry";
|
||||
import { VIEW_TYPE_COI_CHAT } from "@/ChatView";
|
||||
import type CoIntelligencePlugin from "@/CoIntelligencePlugin";
|
||||
import {
|
||||
Source,
|
||||
CoiNoteFrontmatter,
|
||||
ContextItems,
|
||||
ContextItemContent,
|
||||
ChatRequest,
|
||||
Model,
|
||||
} from "@/types";
|
||||
import { Source, CoiNoteFrontmatter, ContextItems } from "@/types";
|
||||
|
||||
const CHAT_START = "<!-- CHAT-THREAD-START -->";
|
||||
const CHAT_END = "<!-- CHAT-THREAD-END -->";
|
||||
|
|
@ -180,16 +173,16 @@ export async function openCOINote(
|
|||
});
|
||||
}
|
||||
|
||||
export async function serializeCoiNoteContent(
|
||||
export function serializeCoiNoteContent(
|
||||
currentNoteContent: string,
|
||||
app: App,
|
||||
_app: App,
|
||||
messages: ModelChatMessage[],
|
||||
contextItems: ContextItems | null,
|
||||
sources?: Source[],
|
||||
): Promise<string> {
|
||||
): string {
|
||||
const serializedMessages = messages
|
||||
.map(({ role, content }) => {
|
||||
const contentStr = content as string;
|
||||
const contentStr = (content as string) || "";
|
||||
|
||||
// Find the highest level header in the content
|
||||
const headerMatches = contentStr.match(/^#+/gm);
|
||||
|
|
@ -267,7 +260,7 @@ export async function serializeCoiNote(
|
|||
return;
|
||||
}
|
||||
|
||||
const newNoteContent = await serializeCoiNoteContent(
|
||||
const newNoteContent = serializeCoiNoteContent(
|
||||
currentNoteContent,
|
||||
app,
|
||||
messages,
|
||||
|
|
@ -305,15 +298,15 @@ export async function deserializeCoiNote(note: TFile, app: App) {
|
|||
);
|
||||
}
|
||||
|
||||
export async function deserializeCoiNoteContent(
|
||||
export function deserializeCoiNoteContent(
|
||||
content: string,
|
||||
metadata: CachedMetadata | null,
|
||||
app: App,
|
||||
): Promise<{
|
||||
): {
|
||||
messages: ModelChatMessage[];
|
||||
contextItems: ContextItems;
|
||||
sources: Source[];
|
||||
}> {
|
||||
} {
|
||||
if (!pattern.test(content)) {
|
||||
return {
|
||||
messages: [],
|
||||
|
|
@ -363,7 +356,7 @@ export async function deserializeCoiNoteContent(
|
|||
flushContent();
|
||||
const candidateMode = line
|
||||
.replace(/^## /, "")
|
||||
.replace(/\:/, "")
|
||||
.replace(/:/, "")
|
||||
.trim()
|
||||
.toLowerCase();
|
||||
if (
|
||||
|
|
|
|||
|
|
@ -5,9 +5,9 @@ export function getDomainFromUrl(url: string): string {
|
|||
try {
|
||||
const urlObj = new URL(url);
|
||||
return urlObj.hostname;
|
||||
} catch (error) {
|
||||
} catch {
|
||||
// If URL parsing fails, try to extract domain manually
|
||||
const match = url.match(/^(?:https?:\/\/)?(?:www\.)?([^\/]+)/);
|
||||
const match = url.match(/^(?:https?:\/\/)?(?:www\.)?([^/]+)/);
|
||||
return match ? match[1] : url;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue