From 744bf754cb2ae82cf2d704adea1017e3584677c8 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Sun, 6 Oct 2024 20:21:04 -0700 Subject: [PATCH] More tools --- chat-tools-sample/README.md | 7 +- chat-tools-sample/cat.jpeg | Bin 50496 -> 0 bytes chat-tools-sample/package-lock.json | 12 +- chat-tools-sample/package.json | 55 ++++++++- chat-tools-sample/src/extension.ts | 36 +----- chat-tools-sample/src/tools.ts | 172 ++++++++++++++++++++++++++++ chat-tools-sample/src/tools.tsx | 19 --- 7 files changed, 235 insertions(+), 66 deletions(-) delete mode 100644 chat-tools-sample/cat.jpeg create mode 100644 chat-tools-sample/src/tools.ts delete mode 100644 chat-tools-sample/src/tools.tsx diff --git a/chat-tools-sample/README.md b/chat-tools-sample/README.md index 8c2a122b..5154cdf7 100644 --- a/chat-tools-sample/README.md +++ b/chat-tools-sample/README.md @@ -13,9 +13,4 @@ This sample shows - Run the extension in a new VS Code window ## TODO -- Read files from references -- Tools - - Something to collect some vscode window context (tab count) - - Something that has a side effect and confirmation- run in terminal? - - Something that returns a large amount of data and uses Prompt-TSX and references- findFiles -- Use prompt-tsx for main prompt \ No newline at end of file +- Use prompt-tsx for main prompt and tools \ No newline at end of file diff --git a/chat-tools-sample/cat.jpeg b/chat-tools-sample/cat.jpeg deleted file mode 100644 index f517cce0e237d5bfa6dd824ccd07fa69ffb6ca2c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 50496 zcmb5VWmpwa*8n<{l%#ZrAl)r3A>Ex)N_VFqAl=gOoH#gLEV1orAvb_ucP# z?vJ|;GiP?p+N<{3Yp;FyGxz5wfG#Z|B>_M|K>=^U5AbIZcmu$~z(D?BVPN54Vd0)3 z!9N251rZ4W2@M4u9SsEy72^dS76v9RCMp^>5jHM9J|Q6?IufuaDQF`!^Dp#Jm#L?EdE6dV-rKL7;}4HAg} z1GW-C_<#Yg{{bjykc(%37J%n4PyjSK3_1Wnjk65Dl|~kR>ZFPdC#p&Vn+*U}niQRe z00I&~0|3yShN}OA0|3YXgnC3pRVsf!Bmn5a2jKoSA{s(>3WLuGpltqk|EFhYXlQ>w zKOn>q0FdF3o{K~SP{PnkP^NwWowOCp>8>sPvf>O=~hyDwRWB>qSr1}gN z;hvBy1Bw8&=D%hDnFc@r{IbEKUp6$fAIOw21@w1>ry5uQP}Kyh0L5%S@B?Lvj)iCl zc7${Tpoc(SK+F)Hz($b7r)o$A6qGPHf*$}76oevxQUHsHhL8scKsW^7BclQQAcR2> z{~H;^L<7LWQGukwTHt&G`+{u#mrwxuZ+B?0zKY@-oHX!+2t@V|@zaPBC8pT`fCT{Y z!eBoTz_*^p3sD3m14siPPf&`g*61+0QROR})kNY&NK42-^P(WHeNw-$C(`fi(Z4)(>Pv6Gs!u5ELKP%PLi@K)?Ut z=)dnnMgn>GuL(dE(~vQMJmNs=SRp1X3=0Q&{(k|eKX5QmYaqZ@0|1JMFl?x1Hf$Bx zAC?aD8$`YkK>zpsw* z=}S!jv6u}c3i1{@$Rr5n3+`bIj)~)=)=Q5AoBXC(mxqJh`rn`0{&OQh@wUZWw{G?( z9Q&=7*F5%o4ZI+L>+m)lrK-_(bYJYWiV)zHxj(}9-2mR3$ z#0E_UfC2`fXh6Y&`28R+yR%og$k#9Kd|f2UZEW{=HJ-e6ivR2IG2wKTwJdKAwPfLU zbM7}t&nJNTe6VxB(eV4yLDg!;Cq1};^WbcCJbwMGbM+S9r~iGSH6Il6g!&w)CE=Z*BMWA3%5j&*q|W z;{al$G@#+gfEPs%0C2*A8bbgp(E-dJunvwtXQo9#{qSeoY=Ns>dPmWL z+Nkc)WxPu?)oKQ=|%Ux{?v76iZg01_(-dQ8wc zDd7O0fG5MuhIl7vaE61lGZe-1ef_Xc+={w0^*VFKYN|**@;G+tq=j#yZ-0%ww&KX` z%WD^1Zu-8HyDX^6V%ThpB)M((5)U0p8>&9pq#8ctx)WF8Se;O5%o3@~10r1JjsW zFkm4(c>xj7C4fqX1t6XP&{BAH=`%HR=SDnU2R{s?0jd(gTsz^dU)qmD$<%-R~V=AyGo7hu7~F?hdvG_0n=&^vARM_-!fs-Twgc z1C2Wrpa{iUGyFh11Q!-?2?W-zN4yd9{5v%QpeE6n-_^rpt~I8*`p zA;e|2vv)Xzc4#7(5^&3T#SzWi4^t%PEjMn;EF9TYt z^J}S_NsW?HYlcLf9_trwixfy_UtJ0=SK3*u#M>ty(_IKGEpglZ5?B=QIvcZ@YgQgZ zuGH``7Aj96xkMdjHr-$KUg33b2^qgZbBVx_t^YL{IN)~PY}_&(k$4@|KuZSF2tWry z7Dmh`uLzmYumBbY1B5_$&GpvVS`EA19ZAL@&B=WIVSKd4{eF*Y7g>#&3)9fvUZdXB zNMBmReYT6uUS19T#q--i5pjx6n%@sJaXUc=N1FYgt*02iVj*7rrW(+a8TE?fy?u@A z%4GTcer&UGbZLt~bbpX%BGRX8tJU)tlTUjm!)!8uB<=?;fuJrSp#!)8K2Zrq8eo_L z^LgupOLKiRXSN%cOeU(rcQ<(_@}PxdX*J+XkoPP(Oh1gOL-l54Jc-lEo$rq6-Payl z)Af-{!=Q8XmW*io3jw}8?)7Y*R1Js3o1-2P2v}*Z293Rg+wKwj!x- zajEw9&YmqUXgt3cyDTJ{FTzDhb;aKqUkV?mSg)9w(fl%-$cOJ(yVf!uxi#hR@+m*VStg>2%+z1|RmrvGD&(-V z@dv2i?rNidY3${V%#fewx))gzcX_zHw{Y>G)3Vw<^k7MQ$XprA9^V!)eZ{H9<`FBS5OVUqs6cFL5A7VkWQH3k=tRgLhw&OO^A-7WjZ zjq%LkPC}0LQk&^qwr$Fh*!MzNQd3D8EBpbwOUS{l>NQ(mncrve-m)jvaUNiSOXO29 z1~CmeFo=g32gE@E02=x2`9PZc4X+-5+co3bLC5@ghfLwY&z{CV0GSi2P%(-(d*XTx zamv(w9dCn=-pGxF)0WracZZ}`dD{o3yMF*Kn~7f}oq^}i#?ZK&ml7f>2Fv8j;vJh> zP%_=N1*}`9rZyg5EP7J*jtd(ew%$Qy7WwS*rbMdk3G_qNJL#T(6fh|JntJ}~OBHoR zy6>I=#jRw~$l;Rhth(2V;>29@kw7-c;cyyH&9k(k+U-KbF&=Ko@>#3a$0Ml=*K`5W z!8w8}KZL3}GB7ZCinIU%(02gh=zu?127oi>iq?p)Ss$4dnC*s>U1_fFk9jMt8|OPi zJm9@{y@V9;oN8>?j3Z{GT{ z*N*is<2E_1pcOsmZerrqPo0T!Abme9|2kIB%`#y8P(KoHFny89CBy9xz^FMJt}j$# z_FQPM-17`?<3bpUfj?)OJrQO9T(710*J9q()W@AWADuGe^o8y+*sCuo)V`#p)@xQ@ z8}m?Z{s3aFzS1y^M!FfbVPvNrg7h8Rm+LF1-+3Q=1k>AB-d^~oKj4FmG=Py37DPo) zp<`+QxIWT=OhJKBJpi>sD(S>fbxx<>PFiI7i=g3rlX3g?;?dfYHL8JHnY>ZTyPc^m z`#ZA{!b(9~xoRenUnjqVf^?hHnT5NHzP^(qaBrJ>VGvku4Tb*vwk|#1#_vfw+G%R{BhL6n4`v|WNio)QTd)T^P9o&-6 z77ZN;NO9cKbH3}~+^+aK&vO^>+z-kWTqr?+qNVr-a6;x2NW3uQ2F)>c#!TGv?{RrwL33bh8xWV@e)8lsQiHQrM2hdQ2A*&|PV@B2&?+U@#ETO`-`#*r`ZpN&FB+SPL0W*Edse{afmaI_?LD}kWscra61?LrZ zN7w3?oVG9ozl&ztRd&}WYkgVjudWQDAA-kc8;KsQ3HnI8RtA3`Osq?m-ZmVPc)!GUK9V+BWDCfk(VfrpUcS-Op6a38M-ZjK<7 zL&7G}kHTO$4=(zMhTt8*>lh~)IsNfy>(6~|mbn(_s9q8L;n&?g`;o_$PMd&`SS<_K zi<)7`GAhhPud?*&cjWjFN3kaQ`gEU!7i6Hy^0Ndyk)v?GdAEE1=GX|2*;%?g`N3u0 zUUnW;esS@O=z#-_)BM5B8W_0!_4bO{ir_4RK!_oDOGFd&K&#k_inS>x*5y0@17x+N zF^tN2zGkMMx)W@>k8G=4)j!VF5)lUHWXjBITjis(iuYZ=GfgulPdz{k&}f;J{^mb< zQLDd7q;XhHOrK=&b{kou0-l?hkp>Y{F1usIW#hc(C@t+OVKYHvi!DFhy>+f{8#=sPya}v^{65HsOjZ2> zNN0KvZQzF&iP*DX@?z#Z4h6DK&lJY9Dj7`v057ivl0CjSxB_17w9OOsH(IUp)_g}E zk9XEt!v;N8)5DGZKNhafD3dDuKyt8!;lRKGBnRA}LkB|4%?}pp-|skLYQc`N)P(VhOj--g->Db0N0(O1Ek?)OPfx5!YlJ?~351-U0vZ+Szf`d91ED_Mg*cnLUHB5l+5Q20tH zVw6Re=S{*Zi!?~>j1xd&poaj^=|cdtAaGy$w8la9s82uyAK#W1*iLxrM^4U1ce8o9aL4QSOzwfAe-05aN#aob6hgo)FxkB@h+r>C8Vlzl+^Yy1; z{4&{oMr|jrFK5ScBbtu2{&@o0xqeW_hlJzmCjzr+Rh-sZ!r*W?idbM&4bX(4V}T-q z0o?{PSPM}hWE}>9l?%8UqgpHi^tAbSnH~3{FDmxOcwP06Hm+`#95;V6)nE4u4qol2 z2l1X0G_K|k$FvYTGA=K^U6yOr8_TF1KZ-n4qtd*>G_GRZd@bX$0zoERGOf> zG4@WSt?4k-6~`@~iM~zMRO4TJ6 zVz_j#$#}`3GSk^OtH=yz;P%ReI)2#xdahury_MX3wa7qb{KFdg$cJ^)w8P3lvl2lo zpU9ZVvlL0J6YJEjpSA5ZzaFD^+~xJl-{{Z8LwJU4iT;NINDuB5y$*-^oZi{iY*Q01;#Yrks~dlK z|NP4_@f%yV9tOgIwSg_7@iHI&!Q1o)%vjKe0N`8(B@PaZqY3V9{rs{as}4jNVEjYz zxe9!E0=_Zgi#H5jdZ$PZ1Z*y70sjT~;a_}}>O+>1NNW!S!=&u@ZLirf zP48|M!JSX~NVr4)a&3ZfeC{Vu9)BePJ@n+nL8FGk`HNK;M23!q{w`F)Y0(&ANGm!vgVDda1V!^UHI*YvD^Kdu z%gB4t&BkoTY_Bfpw3e`8)a3e%IlV1SS$@k&Nr#g zGzBf#guBezYgjF*SS`&gE_WFO94iFgC2f=)L?yPVC8m{NPS9k7!+?MUZZn3c{GL?t z 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%0D+_csf~do`ri^n!1DdA=w%DI7vK-b2P;Da7$v|z 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 ITYZQB+3Z-p^#A|> diff --git a/chat-tools-sample/package-lock.json b/chat-tools-sample/package-lock.json index 5cda7497..b02e530e 100644 --- a/chat-tools-sample/package-lock.json +++ b/chat-tools-sample/package-lock.json @@ -1,15 +1,15 @@ { - "name": "chat-sample", + "name": "chat-tool-sample", "version": "0.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "chat-sample", + "name": "chat-tool-sample", "version": "0.1.0", "devDependencies": { "@types/node": "^20.5.9", - "@types/vscode": "^1.90.0", + "@types/vscode": "^1.94.0", "@vscode/prompt-tsx": "^0.2.7-alpha", "eslint": "^7.22.0", "run-script-os": "^1.1.6", @@ -213,9 +213,9 @@ } }, "node_modules/@types/vscode": { - "version": "1.90.0", - "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.90.0.tgz", - "integrity": "sha512-oT+ZJL7qHS9Z8bs0+WKf/kQ27qWYR3trsXpq46YDjFqBsMLG4ygGGjPaJ2tyrH0wJzjOEmDyg9PDJBBhWg9pkQ==", + "version": "1.94.0", + "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.94.0.tgz", + "integrity": "sha512-UyQOIUT0pb14XSqJskYnRwD2aG0QrPVefIfrW1djR+/J4KeFQ0i1+hjZoaAmeNf3Z2jleK+R2hv+EboG/m8ruw==", "dev": true }, "node_modules/@vscode/prompt-tsx": { diff --git a/chat-tools-sample/package.json b/chat-tools-sample/package.json index 2fff36bf..5238fd87 100644 --- a/chat-tools-sample/package.json +++ b/chat-tools-sample/package.json @@ -1,5 +1,5 @@ { - "name": "chat-tool-sample", + "name": "chat-tools-sample", "publisher": "vscode-samples", "displayName": "Copilot Chat Tools Sample", "description": "Sample chat extension that registers and uses LanguageModelTools", @@ -32,8 +32,8 @@ ], "languageModelTools": [ { - "tags": ["editors", "chat-sample"], - "id": "chat-sample_tabCount", + "id": "chat-tools-sample_tabCount", + "tags": ["editors", "chat-tools-sample"], "name": "tabCount", "displayName": "Tab Count", "modelDescription": "The number of active tabs in a tab group", @@ -49,6 +49,53 @@ } } }, + "supportedContentTypes": [ + "text/plain" + ] + }, + { + "id": "chat-tools-sample_findFiles", + "tags": [ + "files", + "search", + "chat-tools-sample" + ], + "displayName": "Find Files", + "modelDescription": "Search for files in the current workspace", + "parametersSchema": { + "type": "object", + "properties": { + "pattern": { + "type": "string", + "description": "Search for files that match this glob pattern" + } + }, + "required": ["pattern"] + }, + "supportedContentTypes": [ + "text/plain" + ] + }, + { + "id": "chat-tools-sample_runInTerminal", + "tags": [ + "terminal", + "chat-tools-sample" + ], + "displayName": "Run in Terminal", + "modelDescription": "Run a command in a terminal and return the output", + "parametersSchema": { + "type": "object", + "properties": { + "command": { + "type": "string", + "description": "The command to run" + } + }, + "required": [ + "command" + ] + }, "supportedContentTypes": [ "text/plain" ], @@ -64,7 +111,7 @@ }, "devDependencies": { "@types/node": "^20.5.9", - "@types/vscode": "^1.90.0", + "@types/vscode": "^1.94.0", "@vscode/prompt-tsx": "^0.2.7-alpha", "eslint": "^7.22.0", "run-script-os": "^1.1.6", diff --git a/chat-tools-sample/src/extension.ts b/chat-tools-sample/src/extension.ts index 67e7b24a..e368129e 100644 --- a/chat-tools-sample/src/extension.ts +++ b/chat-tools-sample/src/extension.ts @@ -1,6 +1,5 @@ -import { contentType as promptTsxContentType, renderElementJSON } from '@vscode/prompt-tsx'; import * as vscode from 'vscode'; -import { CatVoiceToolResult } from './tools'; +import { FindFilesTool, RunInTerminalTool, TabCountTool } from './tools'; export function activate(context: vscode.ExtensionContext) { registerChatTool(context); @@ -8,35 +7,9 @@ export function activate(context: vscode.ExtensionContext) { } function registerChatTool(context: vscode.ExtensionContext) { - interface ITabCountParameters { - tabGroup?: number; - } - - context.subscriptions.push(vscode.lm.registerTool('chat-sample_tabCount', { - async invoke(options, token) { - await new Promise(resolve => setTimeout(resolve, 5000)); - const params = options.parameters as ITabCountParameters; - if (typeof params.tabGroup === 'number') { - const group = vscode.window.tabGroups.all[Math.max(params.tabGroup - 1, 0)]; - const nth = params.tabGroup === 1 ? '1st' : params.tabGroup === 2 ? '2nd' : params.tabGroup === 3 ? '3rd' : `${params.tabGroup}th`; - return { 'text/plain': `There are ${group.tabs.length} tabs open in the ${nth} tab group.` }; - } else { - const group = vscode.window.tabGroups.activeTabGroup; - return { 'text/plain': `There are ${group.tabs.length} tabs open.` }; - } - }, - prepareToolInvocation: async (options) => { - const confirmationMessages = { - title: 'Count the number of open tabs', - message: new vscode.MarkdownString(`${options.participantName} will count the number of open tabs` + (options.parameters.tabGroup !== undefined ? ` in tab group ${options.parameters.tabGroup}` : '')) - }; - - return { - invocationMessage: 'Counting the number of tabs', - confirmationMessages - } - }, - })); + context.subscriptions.push(vscode.lm.registerTool('chat-tools-sample_tabCount', new TabCountTool())); + context.subscriptions.push(vscode.lm.registerTool('chat-tools-sample_findFiles', new FindFilesTool())); + context.subscriptions.push(vscode.lm.registerTool('chat-tools-sample_runInTerminal', new RunInTerminalTool())); } interface IToolCall { @@ -48,6 +21,7 @@ interface IToolCall { const llmInstructions = `Instructions: - The user will ask a question, or ask you to perform a task, and it may require lots of research to answer correctly. There is a selection of tools that let you perform actions or retrieve helpful context to answer the user's question. - If you aren't sure which tool is relevant, you can call multiple tools. You can call tools repeatedly to take actions or gather as much context as needed until you have completed the task fully. Don't give up unless you are sure the request cannot be fulfilled with the tools you have. +- Don't make assumptions about the situation- gather context first, then perform the task or answer the question. - Don't ask the user for confirmation to use tools, just use them. - After editing a file, DO NOT show the user a codeblock with the edit or new file contents. Assume that the user can see the result.` diff --git a/chat-tools-sample/src/tools.ts b/chat-tools-sample/src/tools.ts new file mode 100644 index 00000000..99fc6a3c --- /dev/null +++ b/chat-tools-sample/src/tools.ts @@ -0,0 +1,172 @@ +import * as vscode from 'vscode'; + +interface ITabCountParameters { + tabGroup?: number; +} + +export class TabCountTool implements vscode.LanguageModelTool { + async invoke( + options: vscode.LanguageModelToolInvocationOptions, + token: vscode.CancellationToken + ) { + const params = options.parameters; + if (typeof params.tabGroup === 'number') { + const group = vscode.window.tabGroups.all[Math.max(params.tabGroup - 1, 0)]; + const nth = + params.tabGroup === 1 + ? '1st' + : params.tabGroup === 2 + ? '2nd' + : params.tabGroup === 3 + ? '3rd' + : `${params.tabGroup}th`; + return { + 'text/plain': `There are ${group.tabs.length} tabs open in the ${nth} tab group.`, + }; + } else { + const group = vscode.window.tabGroups.activeTabGroup; + return { 'text/plain': `There are ${group.tabs.length} tabs open.` }; + } + } + + async prepareToolInvocation( + options: vscode.LanguageModelToolInvocationPrepareOptions, + token: vscode.CancellationToken + ) { + const confirmationMessages = { + title: 'Count the number of open tabs', + message: new vscode.MarkdownString( + `${options.participantName} will count the number of open tabs` + + (options.parameters.tabGroup !== undefined + ? ` in tab group ${options.parameters.tabGroup}` + : '') + ), + }; + + return { + invocationMessage: 'Counting the number of tabs', + confirmationMessages, + }; + } +} + +interface IFindFilesParameters { + pattern: string; +} + +export class FindFilesTool implements vscode.LanguageModelTool { + async invoke( + options: vscode.LanguageModelToolInvocationOptions, + token: vscode.CancellationToken + ) { + const params = options.parameters as IFindFilesParameters; + const files = await vscode.workspace.findFiles( + params.pattern, + '**/node_modules/**', + undefined, + token + ); + + const result: vscode.LanguageModelToolResult = {}; + if (options.requestedContentTypes.includes('text/plain')) { + const strFiles = files.map((f) => f.fsPath).join('\n'); + result[ + 'text/plain' + ] = `Found ${files.length} files matching "${params.pattern}":\n${strFiles}`; + } + + return result; + } + + async prepareToolInvocation( + options: vscode.LanguageModelToolInvocationPrepareOptions, + token: vscode.CancellationToken + ) { + return { + invocationMessage: `Searching workspace for "${options.parameters.pattern}"`, + }; + } +} + +interface IRunInTerminalParameters { + command: string; +} + +async function waitForShellIntegration( + terminal: vscode.Terminal, + timeout: number +): Promise { + let resolve: () => void; + let reject: (e: Error) => void; + let p = new Promise((_resolve, _reject) => { + resolve = _resolve; + reject = _reject; + }); + + const timer = setTimeout(() => reject(new Error('Could not run terminal command: shell integration is not enabled')), timeout); + + const listener = vscode.window.onDidChangeTerminalShellIntegration((e) => { + if (e.terminal === terminal) { + clearTimeout(timer); + listener.dispose(); + resolve(); + } + }); + + await p; +} + +export class RunInTerminalTool + implements vscode.LanguageModelTool +{ + async invoke( + options: vscode.LanguageModelToolInvocationOptions, + token: vscode.CancellationToken + ) { + const result: vscode.LanguageModelToolResult = {}; + const params = options.parameters as IRunInTerminalParameters; + + const terminal = vscode.window.createTerminal('Language Model Tool User'); + terminal.show(); + try { + await waitForShellIntegration(terminal, 5000); + } catch(e) { + if (options.requestedContentTypes.includes('text/plain')) { + result['text/plain'] = (e as Error).message; + } + return result; + } + + const execution = terminal.shellIntegration!.executeCommand(params.command); + const terminalStream = execution.read(); + + let terminalResult = ''; + for await (const chunk of terminalStream) { + terminalResult += chunk; + } + + if (options.requestedContentTypes.includes('text/plain')) { + result['text/plain'] = terminalResult; + } + + return result; + } + + async prepareToolInvocation( + options: vscode.LanguageModelToolInvocationPrepareOptions, + token: vscode.CancellationToken + ) { + const confirmationMessages = { + title: 'Run command in terminal', + message: new vscode.MarkdownString( + `${options.participantName} will run this command in a terminal:` + + `\n\n\`\`\`\n${options.parameters.command}\n\`\`\`\n` + ), + }; + + return { + invocationMessage: `Running command in terminal`, + confirmationMessages, + }; + } +} diff --git a/chat-tools-sample/src/tools.tsx b/chat-tools-sample/src/tools.tsx deleted file mode 100644 index 43b39635..00000000 --- a/chat-tools-sample/src/tools.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import { - BasePromptElementProps, - PromptElement, - PromptSizing, - TextChunk, - UserMessage -} from '@vscode/prompt-tsx'; - -export class CatVoiceToolResult extends PromptElement { - render(state: void, sizing: PromptSizing) { - return ( - <> - - Reply in the voice of a cat! Use cat analogies when appropriate. - - - ); - } -}