Skip to content

Commit 95c9575

Browse files
committed
Merge branch 'dev'
2 parents 1befc8a + d2c573d commit 95c9575

50 files changed

Lines changed: 1206 additions & 758 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎README.md‎

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
<a href="https://marketplace.visualstudio.com/items?itemName=robertpiosik.gemini-coder" target="_blank"><img src="https://img.shields.io/badge/Install-VS_Code_Marketplace-blue" alt="Get from Visual Studio Code Marketplace" /></a> <a href="https://open-vsx.org/extension/robertpiosik/gemini-coder" target="_blank"><img src="https://img.shields.io/badge/Install-Open_VSX_Registry-a60ee5" alt="Get from Open VSX Registry" /></a> <a href="https://github.com/robertpiosik/CodeWebChat/blob/dev/LICENSE" target="_blank"><img src="https://img.shields.io/badge/License-GPL--3.0-green.svg" alt="GPL-3.0 license" /></a>
44

5-
**Meet Code Web Chat, the privacy AI coding without agents.** Guide the model to production-grade code with engineer-level control over context. Community-driven, free and open-source.
5+
AI coding without agents. Guide the model to production-grade code with engineer-level control over context.
66

77
Works with VS Code, and forks like Cursor, Windsurf, and VSCodium.
88

@@ -13,7 +13,9 @@ Works with VS Code, and forks like Cursor, Windsurf, and VSCodium.
1313

1414
✅ **Apply responses**—sophisticated markdown parser for multi-file changes integration \
1515
✅ **Fully featured**—code completions, commit messages, checkpoints, and more \
16-
🔒️ **Total privacy**—operates 100% on your local machine
16+
❤️ **Free and open-source**—released under the GPL-3.0 license \
17+
🔒️ **Total privacy**—operates 100% on your local machine \
18+
👥 **Community driven**—join our [Discord server](https://discord.com/invite/KJySXsrSX5) and get involved!
1719

1820
<p>
1921
<img src="https://github.com/robertpiosik/CodeWebChat/raw/HEAD/packages/shared/src/media/demo.gif" alt="Walkthrough" />
@@ -25,17 +27,17 @@ Works with VS Code, and forks like Cursor, Windsurf, and VSCodium.
2527

2628
Code Web Chat helps you use your favorite coding web tools like ChatGPT's canvas. The idea to initialize chatbots is borrowed from [Firefox](https://support.mozilla.org/en-US/kb/ai-chatbot) and because there is no further automation once the prompt is sent, by using CWC you're not violating their Terms of Use. Contributors should not submit pull requests implementing further chat automations of any kind, as these will be kindly rejected.
2729

28-
🧑‍💻 **The limitations of LLMs**
30+
🧐 **The limitations of LLMs**
2931

3032
Large language models (LLMs) are trained on vast datasets targeting many use cases. For code generation, a model's training involves analyzing millions of simulated problem-solving flows, such as arriving at the accepted answer from a given StackOverflow question. For the purpose of agentic coding, models are trained on an additional layer of data that simulates gathering context and planning its next steps.
3133

3234
Because the model is only as smart as examples it has seen in its pre-training stage, the possible coverage of real-world problems when approached at a high level is fundamentally limited.
3335

3436
Therefore, CWC is designed to align with LLMs' true capabilities—that is, code generation in a controlled signal-to-noise ratio environment. Controlled by you, the engineer.
3537

36-
🙋 **Guide the model with context**
38+
🧠 **Guide the model with context**
3739

38-
Unlike coding agents that require detailed instructions to understand your intent and locate relevant files, CWC lets you provide full context up front allowing much simpler instructions. This saves money and time—the model doesn't have to make any tool calls, which are distracting "side quests".
40+
Unlike coding agents that require detailed instructions to understand your intent and locate relevant files, with CWC you provide fine-grained context up front, allowing simple, even vague instructions.
3941

4042
> [!TIP]
4143
> LLMs are pattern matchers—they love examples! Include some you believe will help the model understand the goal better.

‎packages/shared/src/constants/dictionary.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ export const dictionary = {
6868
'Cannot copy prompt in edit context mode without any context. Please add files to the context.',
6969
CANNOT_COPY_PROMPT_IN_CODE_COMPLETION_WITHOUT_EDITOR:
7070
'Cannot copy prompt in code completion mode without an active editor.',
71-
UNABLE_TO_WORK_WITH_EMPTY_CONTEXT: 'Unable to work with empty context.',
71+
CONTEXT_CANNOT_BE_EMPTY: 'Context cannot be empty.',
7272
INSTRUCTIONS_CANNOT_BE_EMPTY: 'Instructions cannot be empty.',
7373
CANNOT_PREVIEW_IN_CODE_COMPLETION_WITHOUT_EDITOR:
7474
'Cannot preview in code completion mode without an active editor.',

‎packages/ui/src/components/editor/common/Input/Input.tsx‎

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,25 @@ import styles from './Input.module.scss'
33
type Props = {
44
id?: string
55
type?: string
6-
value: string
6+
value: string | number
77
placeholder?: string
88
max_width?: number
9+
width?: number
910
onChange: (value: string) => void
1011
onKeyDown?: (e: React.KeyboardEvent<HTMLInputElement>) => void
12+
min?: number
13+
max?: number
14+
step?: number
1115
}
1216

1317
export const Input: React.FC<Props> = (props) => {
14-
const style = props.max_width
15-
? { maxWidth: `${props.max_width}px` }
16-
: undefined
18+
const style: React.CSSProperties = {}
19+
if (props.max_width) {
20+
style.maxWidth = `${props.max_width}px`
21+
}
22+
if (props.width) {
23+
style.width = `${props.width}px`
24+
}
1725

1826
return (
1927
<input
@@ -24,7 +32,10 @@ export const Input: React.FC<Props> = (props) => {
2432
onKeyDown={props.onKeyDown}
2533
className={styles.input}
2634
placeholder={props.placeholder}
27-
style={style}
35+
style={Object.keys(style).length > 0 ? style : undefined}
36+
min={props.min}
37+
max={props.max}
38+
step={props.step}
2839
/>
2940
)
3041
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
.textarea {
2+
border: 1px solid var(--cwc-border-color);
3+
background: var(--vscode-input-background);
4+
color: var(--vscode-input-foreground);
5+
padding: var(--padding-4px) var(--padding-7px);
6+
border-radius: var(--border-radius-4px);
7+
width: 100%;
8+
resize: none;
9+
overflow: hidden;
10+
11+
&:hover {
12+
border-color: var(--cwc-border-color-hover);
13+
}
14+
15+
&:focus {
16+
outline: none;
17+
border-color: var(--vscode-focusBorder);
18+
}
19+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { useState } from 'react'
2+
import { Textarea } from './Textarea'
3+
4+
export default {
5+
component: Textarea
6+
}
7+
8+
export const Primary = () => {
9+
const [value, set_value] = useState('')
10+
11+
return (
12+
<Textarea
13+
value={value}
14+
on_change={set_value}
15+
placeholder="Enter text here"
16+
min_rows={3}
17+
/>
18+
)
19+
}
20+
21+
export const WithValue = () => {
22+
const [value, set_value] = useState(
23+
'Initial value\nThis is a multiline text area.'
24+
)
25+
26+
return (
27+
<Textarea
28+
value={value}
29+
on_change={set_value}
30+
placeholder="Will be ignored because value is set"
31+
min_rows={3}
32+
/>
33+
)
34+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import React from 'react'
2+
import TextareaAutosize from 'react-textarea-autosize'
3+
import styles from './Textarea.module.scss'
4+
5+
type Props = {
6+
id?: string
7+
value?: string
8+
placeholder?: string
9+
min_rows?: number
10+
max_rows?: number
11+
on_change: (value: string) => void
12+
on_key_down?: (e: React.KeyboardEvent<HTMLTextAreaElement>) => void
13+
onFocus?: (e: React.FocusEvent<HTMLTextAreaElement>) => void
14+
}
15+
16+
export const Textarea = React.forwardRef<HTMLTextAreaElement, Props>(
17+
(props, ref) => {
18+
return (
19+
<TextareaAutosize
20+
id={props.id}
21+
value={props.value}
22+
onChange={(e) => props.on_change(e.target.value)}
23+
onKeyDown={props.on_key_down}
24+
className={styles.textarea}
25+
placeholder={props.placeholder}
26+
minRows={props.min_rows}
27+
maxRows={props.max_rows}
28+
onFocus={props.onFocus}
29+
ref={ref}
30+
/>
31+
)
32+
}
33+
)
34+
35+
Textarea.displayName = 'Textarea'
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './Textarea'

‎packages/ui/src/components/editor/panel/Configurations/Configurations.module.scss‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,29 @@
33
flex-direction: column;
44
}
55

6+
.header {
7+
height: var(--list-item-height);
8+
padding: 0 var(--padding-12px);
9+
display: flex;
10+
justify-content: space-between;
11+
align-items: center;
12+
cursor: pointer;
13+
14+
&:hover {
15+
background-color: var(--vscode-list-hoverBackground);
16+
}
17+
18+
&__left {
19+
display: flex;
20+
align-items: center;
21+
gap: var(--padding-4px);
22+
}
23+
24+
&__right {
25+
display: flex;
26+
}
27+
}
28+
629
.missing-config {
730
padding: var(--padding-2px) var(--padding-12px) 0 var(--padding-12px);
831
font-weight: 500;

‎packages/ui/src/components/editor/panel/Configurations/Configurations.tsx‎

Lines changed: 93 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import styles from './Configurations.module.scss'
22
import { DEFAULT_TEMPERATURE } from '@shared/constants/api-tools'
33
import cn from 'classnames'
44
import { ReactSortable } from 'react-sortablejs'
5-
import { Button } from '../Button/Button'
5+
import { IconButton } from '../IconButton/IconButton'
66

77
export namespace Configurations {
88
export type Configuration = {
@@ -21,82 +21,109 @@ export namespace Configurations {
2121
on_reorder?: (configurations: Configuration[]) => void
2222
selected_configuration_id?: string
2323
on_manage_configurations: () => void
24+
is_collapsed: boolean
25+
on_toggle_collapsed: (is_collapsed: boolean) => void
2426
}
2527
}
2628

2729
export const Configurations: React.FC<Configurations.Props> = (props) => {
2830
return (
2931
<div className={styles.container}>
30-
<div className={styles.configurations}>
31-
<ReactSortable
32-
list={props.configurations}
33-
setList={(new_state) => {
34-
if (props.on_reorder) {
35-
props.on_reorder(new_state)
36-
}
37-
}}
38-
animation={150}
39-
handle={`.${styles.configurations__item__left__drag_handle}`}
40-
disabled={!props.on_reorder}
41-
>
42-
{props.configurations.map((configuration) => {
43-
const description_parts = [configuration.provider]
44-
if (configuration.reasoning_effort) {
45-
description_parts.push(`${configuration.reasoning_effort}`)
46-
}
47-
if (
48-
configuration.temperature &&
49-
configuration.temperature != DEFAULT_TEMPERATURE[props.api_mode]
50-
) {
51-
description_parts.push(`${configuration.temperature}`)
52-
}
53-
if (configuration.cache_enabled) {
54-
description_parts.push('cache-enabled')
55-
}
32+
<div
33+
className={styles.header}
34+
onClick={() => props.on_toggle_collapsed(!props.is_collapsed)}
35+
role="button"
36+
>
37+
<div className={styles.header__left}>
38+
<span
39+
className={cn('codicon', {
40+
'codicon-chevron-down': !props.is_collapsed,
41+
'codicon-chevron-right': props.is_collapsed
42+
})}
43+
/>
44+
<span>Configurations</span>
45+
</div>
46+
<div className={styles.header__right}>
47+
<IconButton
48+
codicon_icon="edit"
49+
on_click={(e) => {
50+
e.stopPropagation()
51+
props.on_manage_configurations()
52+
}}
53+
title="Edit Configurations"
54+
/>
55+
</div>
56+
</div>
57+
{!props.is_collapsed && (
58+
<>
59+
<div className={styles.configurations}>
60+
<ReactSortable
61+
list={props.configurations}
62+
setList={(new_state) => {
63+
if (props.on_reorder) {
64+
props.on_reorder(new_state)
65+
}
66+
}}
67+
animation={150}
68+
handle={`.${styles.configurations__item__left__drag_handle}`}
69+
disabled={!props.on_reorder}
70+
>
71+
{props.configurations.map((configuration) => {
72+
const description_parts = [configuration.provider]
73+
if (configuration.reasoning_effort) {
74+
description_parts.push(`${configuration.reasoning_effort}`)
75+
}
76+
if (
77+
configuration.temperature &&
78+
configuration.temperature !=
79+
DEFAULT_TEMPERATURE[props.api_mode]
80+
) {
81+
description_parts.push(`${configuration.temperature}`)
82+
}
83+
if (configuration.cache_enabled) {
84+
description_parts.push('cache-enabled')
85+
}
5686

57-
const description = description_parts.join(' · ')
87+
const description = description_parts.join(' · ')
5888

59-
return (
60-
<div
61-
key={configuration.id}
62-
className={cn(styles.configurations__item, {
63-
[styles['configurations__item--highlighted']]:
64-
props.selected_configuration_id == configuration.id
65-
})}
66-
onClick={() => {
67-
props.on_configuration_click(configuration.id)
68-
}}
69-
role="button"
70-
>
71-
<div className={styles.configurations__item__left}>
89+
return (
7290
<div
73-
className={cn(
74-
styles.configurations__item__left__drag_handle,
75-
{
76-
[styles[
77-
'configurations__item__left__drag_handle--disabled'
78-
]]: !props.on_reorder
79-
}
80-
)}
81-
onClick={(e) => e.stopPropagation()}
91+
key={configuration.id}
92+
className={cn(styles.configurations__item, {
93+
[styles['configurations__item--highlighted']]:
94+
props.selected_configuration_id == configuration.id
95+
})}
96+
onClick={() => {
97+
props.on_configuration_click(configuration.id)
98+
}}
99+
role="button"
82100
>
83-
<span className="codicon codicon-gripper" />
84-
</div>
85-
<div className={styles.configurations__item__left__text}>
86-
<span>{configuration.model}</span>
87-
<span>{description}</span>
101+
<div className={styles.configurations__item__left}>
102+
<div
103+
className={cn(
104+
styles.configurations__item__left__drag_handle,
105+
{
106+
[styles[
107+
'configurations__item__left__drag_handle--disabled'
108+
]]: !props.on_reorder
109+
}
110+
)}
111+
onClick={(e) => e.stopPropagation()}
112+
>
113+
<span className="codicon codicon-gripper" />
114+
</div>
115+
<div className={styles.configurations__item__left__text}>
116+
<span>{configuration.model}</span>
117+
<span>{description}</span>
118+
</div>
119+
</div>
88120
</div>
89-
</div>
90-
</div>
91-
)
92-
})}
93-
</ReactSortable>
94-
</div>
95-
<div className={styles.footer}>
96-
<Button on_click={props.on_manage_configurations}>
97-
Edit Configurations
98-
</Button>
99-
</div>
121+
)
122+
})}
123+
</ReactSortable>
124+
</div>
125+
</>
126+
)}
100127
</div>
101128
)
102129
}

0 commit comments

Comments
 (0)