-
Notifications
You must be signed in to change notification settings - Fork 3
feat: Add a panel to invoke and talk with Seer #318
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
ryan953
wants to merge
2
commits into
main
Choose a base branch
from
ryan953/seer-panel
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+950
−14
Open
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| import type {SVGIconProps} from 'toolbar/components/icon/SVGIconBase'; | ||
| import SVGIconBase from 'toolbar/components/icon/SVGIconBase'; | ||
|
|
||
| interface Props extends SVGIconProps { | ||
| animation?: 'loading' | 'waiting'; | ||
| } | ||
|
|
||
| export default function IconSeer({animation, ...props}: Props) { | ||
| const commonPath = | ||
| 'M8.01759 0.25C8.23262 0.249787 8.43757 0.341936 8.58009 0.50293C9.70729 1.77804 11.2269 3.70119 12.626 5.82324C13.9841 7.8832 15.2561 10.1746 15.9317 12.2656C15.9736 12.3357 16.005 12.4135 16.0225 12.4971C16.0949 12.8447 15.9134 13.1959 15.5879 13.3379C13.4024 14.2912 11.151 15 8.01857 15C4.88669 15 2.63318 14.2943 0.451185 13.3457C0.17589 13.226 -0.00176762 12.9535 1.33514e-05 12.6533C0.00080069 12.526 0.0359022 12.4049 0.0947399 12.2979C0.767604 10.203 2.04619 7.9014 3.41115 5.83105C4.81012 3.70913 6.32944 1.78347 7.45607 0.503906L7.51173 0.447266C7.64909 0.321318 7.82933 0.250248 8.01759 0.25ZM13.666 10.6562C12.0686 11.1903 10.117 11.5 8.01857 11.5C5.92124 11.5 3.96583 11.1911 2.37111 10.6572C2.11538 11.1963 1.88727 11.7258 1.69923 12.2402C3.54489 12.9877 5.45222 13.5 8.01857 13.5C10.5835 13.5 12.4883 12.9863 14.336 12.2354C14.1485 11.7218 13.9206 11.1939 13.666 10.6562ZM8.01857 5.5C5.93882 5.50013 4.03972 6.99814 3.14259 9.3291C4.50943 9.74712 6.18916 9.99997 8.01857 10C9.84849 9.99998 11.5258 9.74671 12.8955 9.32812C11.9966 6.998 10.098 5.50012 8.01857 5.5ZM8.01954 2.15234C7.51245 2.75664 6.94957 3.46183 6.37013 4.23438C6.89523 4.08216 7.44681 4.00003 8.01857 4C8.59213 4.00002 9.14526 4.08221 9.67189 4.23535C9.09134 3.46176 8.52751 2.756 8.01954 2.15234Z'; | ||
|
|
||
| if (animation === 'waiting') { | ||
| const waitingClassName = 'pupil-waiting'; | ||
| return ( | ||
| <SVGIconBase {...props}> | ||
| <style>{` | ||
| @keyframes moveHorizontal { | ||
| 0% { transform: translateX(0); } | ||
| 5%, 40% { transform: translateX(-1.6px); } | ||
| 50%, 95% { transform: translateX(1.6px); } | ||
| 100% { transform: translateX(0); } | ||
| } | ||
|
|
||
| .${waitingClassName} { | ||
| animation: moveHorizontal 4s ease-out infinite; | ||
| } | ||
| `}</style> | ||
| <path d={commonPath} /> | ||
| <circle className={waitingClassName} cx="8" cy="9" r="2" /> | ||
| </SVGIconBase> | ||
| ); | ||
| } | ||
|
|
||
| if (animation === 'loading') { | ||
| return ( | ||
| <SVGIconBase {...props}> | ||
| <path d={commonPath} /> | ||
| <circle r="2"> | ||
| <animateMotion path="M 8 7 A 1 1 0 0 1 8 9 A 1 1 0 0 1 8 7" dur="1s" repeatCount="indefinite" /> | ||
| </circle> | ||
| </SVGIconBase> | ||
| ); | ||
| } | ||
|
|
||
| return ( | ||
| <SVGIconBase {...props}> | ||
| <path d="M8 0.25C8.21 0.25 8.42 0.34 8.56 0.5C9.69 1.78 11.21 3.7 12.61 5.82C13.97 7.88 15.24 10.17 15.91 12.27C15.96 12.34 15.99 12.41 16 12.5C16.08 12.84 15.89 13.2 15.57 13.34C13.38 14.29 11.13 15 8 15C4.87 15 2.61 14.29 0.43 13.35C0.16 13.23 -0.02 12.95 -0.02 12.65C-0.02 12.53 0.02 12.4 0.08 12.3C0.75 10.2 2.03 7.9 3.39 5.83C4.79 3.71 6.31 1.78 7.44 0.5L7.49 0.45C7.63 0.32 7.81 0.25 8 0.25ZM13.65 10.66C12.05 11.19 10.1 11.5 8 11.5C5.9 11.5 3.95 11.19 2.35 10.66C2.1 11.2 1.87 11.73 1.68 12.24C3.53 12.99 5.43 13.5 8 13.5C10.56 13.5 12.47 12.99 14.32 12.24C14.13 11.72 13.9 11.19 13.65 10.66ZM8 5.5C5.92 5.5 4.02 7 3.12 9.33C4.03 9.61 5.08 9.81 6.22 9.92C6.08 9.64 6 9.33 6 9C6 7.9 6.9 7 8 7C9.1 7 10 7.9 10 9C10 9.33 9.92 9.64 9.78 9.92C10.92 9.81 11.96 9.61 12.88 9.33C11.98 7 10.08 5.5 8 5.5ZM8 2.15C7.49 2.76 6.93 3.46 6.35 4.23C6.88 4.08 7.43 4 8 4C8.57 4 9.13 4.08 9.65 4.24C9.07 3.46 8.51 2.76 8 2.15Z" /> | ||
| </SVGIconBase> | ||
| ); | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,79 @@ | ||
| import LoadingSpinner from 'toolbar/components/base/LoadingSpinner'; | ||
| import type {SeerExplorerBlock} from 'toolbar/sentryApi/types/seerExplorer'; | ||
|
|
||
| interface ChatMessageProps { | ||
| block: SeerExplorerBlock; | ||
| } | ||
|
|
||
| // Validate URL to prevent XSS via javascript: protocol | ||
| function isSafeUrl(url: string): boolean { | ||
| try { | ||
| const parsed = new URL(url); | ||
| return ['http:', 'https:'].includes(parsed.protocol); | ||
| } catch { | ||
| return false; | ||
| } | ||
| } | ||
|
|
||
| export default function ChatMessage({block}: ChatMessageProps) { | ||
| const {message, loading} = block; | ||
| const isUser = message.role === 'user'; | ||
|
|
||
| return ( | ||
| <div | ||
| className={`flex flex-col gap-1 border-b border-b-translucentGray-200 px-2 py-2 ${ | ||
| isUser ? 'bg-translucentGray-100' : '' | ||
| }`}> | ||
| <div className="flex flex-row items-center gap-1"> | ||
| <span className={`text-xs font-medium ${isUser ? 'text-purple-400' : 'text-gray-300'}`}> | ||
| {isUser ? 'You' : 'Seer'} | ||
| </span> | ||
| {loading && <LoadingSpinner size="mini" />} | ||
| </div> | ||
| <div className="whitespace-pre-wrap text-sm text-gray-300">{message.content}</div> | ||
|
|
||
| {/* Show thinking content if available */} | ||
| {message.thinking_content && ( | ||
| <details className="mt-1"> | ||
| <summary className="cursor-pointer text-xs text-gray-400">Show thinking</summary> | ||
| <div className="mt-1 whitespace-pre-wrap text-xs text-gray-400"> | ||
| {message.thinking_content} | ||
| </div> | ||
| </details> | ||
| )} | ||
|
|
||
| {/* Show tool calls if available */} | ||
| {message.tool_calls && message.tool_calls.length > 0 && ( | ||
| <div className="mt-1 flex flex-col gap-0.5"> | ||
| {message.tool_calls.map(toolCall => ( | ||
| <div key={toolCall.id} className="text-xs text-gray-400"> | ||
| 🔧 {toolCall.function?.name || toolCall.type} | ||
| </div> | ||
| ))} | ||
| </div> | ||
| )} | ||
|
|
||
| {/* Show tool links if available */} | ||
| {block.tool_links && block.tool_links.length > 0 && ( | ||
| <div className="mt-1 flex flex-col gap-0.5"> | ||
| {block.tool_links.map((link, idx) => | ||
| isSafeUrl(link.url) ? ( | ||
| <a | ||
| key={idx} | ||
| href={link.url} | ||
| target="_blank" | ||
| rel="noopener noreferrer" | ||
| className="text-xs text-purple-400 hover:underline"> | ||
| 🔗 {link.title} | ||
| </a> | ||
| ) : ( | ||
| <span key={idx} className="text-xs text-gray-400"> | ||
| 🔗 {link.title} (invalid URL) | ||
| </span> | ||
| ) | ||
| )} | ||
| </div> | ||
| )} | ||
| </div> | ||
| ); | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Undefined variable
csrfcauses runtime errorHigh Severity
The variable
csrfis referenced in the headers object on line 101 (...csrf), but its declaration on line 94 is commented out. This causes aReferenceError: csrf is not definedwhenfetchProxyis invoked, breaking all API calls made through the toolbar's fetch proxy.Additional Locations (1)
mock/server/public/toolbar/iframe.html#L93-L94