Skip to content

Commit 753b50d

Browse files
committed
Merge branch 'main' into cs-7850-find-a-way-to-stream-incoming-tool-call-code-and-thinking-ii
2 parents 621f598 + 160dab0 commit 753b50d

File tree

12 files changed

+282
-44
lines changed

12 files changed

+282
-44
lines changed

packages/boxel-ui/addon/src/components/button/index.gts

+1-1
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ export default class ButtonComponent extends Component<Signature> {
103103
height: min-content;
104104
align-items: center;
105105
border-radius: 100px;
106-
white-space: nowrap;
106+
word-break: var(--boxel-button-word-break, break-word);
107107
transition:
108108
background-color var(--boxel-transition),
109109
border var(--boxel-transition);

packages/host/app/components/ai-assistant/chat-input/index.gts

+16-8
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,14 @@ export default class AiAssistantChatInput extends Component<Signature> {
6363
.chat-input {
6464
height: var(--chat-input-height);
6565
min-height: var(--chat-input-height);
66+
max-height: 300px;
6667
border-color: transparent;
6768
font-weight: 500;
6869
padding: var(--boxel-sp-4xs);
6970
resize: none;
7071
outline: 0;
72+
transition: height 0.2s ease-in-out;
73+
overflow-y: auto;
7174
}
7275
.chat-input::placeholder {
7376
color: var(--boxel-400);
@@ -134,17 +137,22 @@ export default class AiAssistantChatInput extends Component<Signature> {
134137
get height() {
135138
const lineHeight = 20;
136139
const padding = 8;
140+
const minLines = 1;
141+
const maxLines = 15;
137142

138-
let lineCount = (this.args.value.match(/\n/g) ?? []).length + 1;
139-
let count = 1;
143+
// Calculate actual line count from newlines in the content
144+
let newlineCount = (this.args.value.match(/\n/g) ?? []).length;
140145

141-
if (lineCount > 5) {
142-
count = 5;
143-
} else if (lineCount > 1) {
144-
count = lineCount;
145-
}
146+
// Also consider content length for lines that might wrap
147+
// This is a rough estimate that can be adjusted
148+
const charsPerLine = 60;
149+
let charLineCount = Math.ceil(this.args.value.length / charsPerLine);
150+
151+
// Use whichever count is higher (newlines or character-based estimate)
152+
let estimatedLineCount = Math.max(newlineCount + 1, charLineCount);
153+
let lineCount = Math.min(Math.max(estimatedLineCount, minLines), maxLines);
146154

147-
let height = count * lineHeight + 2 * padding;
155+
let height = lineCount * lineHeight + 2 * padding;
148156
return `${height}px`;
149157
}
150158
}

packages/host/app/components/matrix/room.gts

+5-1
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ import { AiAssistantConversation } from '../ai-assistant/message';
5757
import NewSession from '../ai-assistant/new-session';
5858
import AiAssistantSkillMenu from '../ai-assistant/skill-menu';
5959

60+
import { Submodes } from '../submode-switcher';
61+
6062
import RoomMessage from './room-message';
6163

6264
import type RoomData from '../../lib/matrix-classes/room';
@@ -300,7 +302,9 @@ export default class Room extends Component<Signature> {
300302
}
301303

302304
private get autoAttachedFile() {
303-
return this.autoAttachedFileResource.value;
305+
return this.operatorModeStateService.state.submode === Submodes.Code
306+
? this.autoAttachedFileResource.value
307+
: undefined;
304308
}
305309

306310
private get removeAutoAttachedFile() {

packages/host/app/components/operator-mode/card-adoption-chain.gts

+3-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import Component from '@glimmer/component';
33

44
import { LoadingIndicator } from '@cardstack/boxel-ui/components';
55

6-
import { type ResolvedCodeRef } from '@cardstack/runtime-common/code-ref';
6+
import { type CodeRef } from '@cardstack/runtime-common/code-ref';
77
import { ModuleSyntax } from '@cardstack/runtime-common/module-syntax';
88

99
import CardSchemaEditor from '@cardstack/host/components/operator-mode/card-schema-editor';
@@ -24,8 +24,9 @@ interface Signature {
2424
moduleSyntax: ModuleSyntax;
2525
isReadOnly: boolean;
2626
goToDefinition: (
27-
codeRef: ResolvedCodeRef | undefined,
27+
codeRef: CodeRef | undefined,
2828
localName: string | undefined,
29+
fieldName?: string,
2930
) => void;
3031
isLoading: boolean;
3132
};

packages/host/app/components/operator-mode/card-schema-editor.gts

+55-6
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import { ArrowTopLeft, IconLink, IconPlus } from '@cardstack/boxel-ui/icons';
2020

2121
import { getPlural } from '@cardstack/runtime-common';
2222

23-
import { type ResolvedCodeRef } from '@cardstack/runtime-common/code-ref';
23+
import { type CodeRef } from '@cardstack/runtime-common/code-ref';
2424
import type { ModuleSyntax } from '@cardstack/runtime-common/module-syntax';
2525

2626
import EditFieldModal from '@cardstack/host/components/operator-mode/edit-field-modal';
@@ -57,8 +57,9 @@ interface Signature {
5757
childFields: string[];
5858
parentFields: string[];
5959
goToDefinition: (
60-
codeRef: ResolvedCodeRef | undefined,
60+
codeRef: CodeRef | undefined,
6161
localName: string | undefined,
62+
fieldName?: string,
6263
) => void;
6364
};
6465
}
@@ -91,6 +92,8 @@ export default class CardSchemaEditor extends Component<Signature> {
9192
border-radius: var(--code-mode-container-border-radius);
9293
background-color: var(--boxel-light);
9394
overflow: hidden;
95+
cursor: pointer;
96+
width: 100%;
9497
}
9598
.card-field + .card-field {
9699
margin-top: var(--boxel-sp-xxs);
@@ -163,6 +166,13 @@ export default class CardSchemaEditor extends Component<Signature> {
163166
overflow: hidden;
164167
text-overflow: ellipsis;
165168
white-space: nowrap;
169+
border: none;
170+
background-color: transparent;
171+
padding: 0;
172+
text-align: left;
173+
}
174+
.field-name:hover {
175+
color: var(--boxel-highlight);
166176
}
167177
168178
.overridden-field {
@@ -244,7 +254,10 @@ export default class CardSchemaEditor extends Component<Signature> {
244254
<Pill
245255
class='field-pill'
246256
@kind='button'
247-
{{on 'click' (fn @goToDefinition codeRef @cardType.localName)}}
257+
{{on
258+
'click'
259+
(fn @goToDefinition codeRef @cardType.localName undefined)
260+
}}
248261
data-test-card-schema-navigational-button
249262
>
250263
<:iconLeft>
@@ -293,15 +306,17 @@ export default class CardSchemaEditor extends Component<Signature> {
293306
data-test-field-name={{field.name}}
294307
>
295308
<div class='left'>
296-
<div
309+
<button
297310
class={{if
298311
(this.isOverridden field)
299312
'field-name overridden-field'
300313
'field-name'
301314
}}
315+
data-test-field-name-button={{field.name}}
316+
{{on 'click' (fn this.goToField field)}}
302317
>
303318
{{field.name}}
304-
</div>
319+
</button>
305320
<div class='field-types' data-test-field-types>
306321
{{this.fieldTypes field}}
307322
</div>
@@ -333,7 +348,12 @@ export default class CardSchemaEditor extends Component<Signature> {
333348
@kind='button'
334349
{{on
335350
'click'
336-
(fn @goToDefinition codeRef field.card.localName)
351+
(fn
352+
@goToDefinition
353+
codeRef
354+
field.card.localName
355+
undefined
356+
)
337357
}}
338358
data-test-card-schema-field-navigational-button
339359
>
@@ -544,4 +564,33 @@ export default class CardSchemaEditor extends Component<Signature> {
544564
inline: 'nearest',
545565
});
546566
}
567+
568+
@action
569+
private goToField(field: FieldOfType) {
570+
if (
571+
`${this.args.cardType.module}.gts` ===
572+
this.operatorModeStateService.codePathString
573+
) {
574+
// In the same file
575+
this.args.goToDefinition(
576+
undefined,
577+
this.args.cardType.localName,
578+
field.name,
579+
);
580+
return;
581+
}
582+
583+
let codeRef = getCodeRef(this.args.cardType);
584+
if (!codeRef) {
585+
return undefined;
586+
}
587+
this.args.goToDefinition(
588+
{
589+
type: 'fieldOf',
590+
card: codeRef,
591+
field: field.name,
592+
},
593+
this.args.cardType.localName,
594+
);
595+
}
547596
}

packages/host/app/components/operator-mode/code-editor.gts

+54-8
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,9 @@ interface Signature {
4545
saveSourceOnClose: (url: URL, content: string) => void;
4646
selectDeclaration: (declaration: ModuleDeclaration) => void;
4747
onFileSave: (status: 'started' | 'finished') => void;
48-
onSetup: (updateCursorByName: (name: string) => void) => void;
48+
onSetup: (
49+
updateCursorByName: (name: string, fieldName?: string) => void,
50+
) => void;
4951
};
5052
}
5153

@@ -137,12 +139,36 @@ export default class CodeEditor extends Component<Signature> {
137139
}
138140
}
139141

142+
let selectedFieldName = this.operatorModeStateService.state.fieldSelection;
143+
let { selectedDeclaration } = this.args;
144+
if (
145+
selectedFieldName &&
146+
selectedDeclaration &&
147+
'possibleFields' in selectedDeclaration &&
148+
selectedDeclaration.possibleFields
149+
) {
150+
let possibleFields = selectedDeclaration.possibleFields;
151+
let field = possibleFields.get(selectedFieldName);
152+
let loc =
153+
field?.path?.node && 'loc' in field.path.node && field.path.node.loc
154+
? field.path.node.loc
155+
: undefined;
156+
if (loc) {
157+
let { start } = loc;
158+
let { line, column } = start;
159+
// Adjusts column to make cursor position right after the field name
160+
let fieldDecoratorTextLength = 8;
161+
column = column + fieldDecoratorTextLength + selectedFieldName.length;
162+
return new Position(line, column);
163+
}
164+
}
165+
140166
let loc =
141-
this.args.selectedDeclaration?.path?.node &&
142-
'body' in this.args.selectedDeclaration.path.node &&
143-
'loc' in this.args.selectedDeclaration.path.node.body &&
144-
this.args.selectedDeclaration.path.node.body.loc
145-
? this.args.selectedDeclaration?.path?.node.body.loc
167+
selectedDeclaration?.path?.node &&
168+
'body' in selectedDeclaration.path.node &&
169+
'loc' in selectedDeclaration.path.node.body &&
170+
selectedDeclaration.path.node.body.loc
171+
? selectedDeclaration?.path?.node.body.loc
146172
: undefined;
147173
if (loc) {
148174
let { start } = loc;
@@ -152,17 +178,37 @@ export default class CodeEditor extends Component<Signature> {
152178
}
153179

154180
@action
155-
private updateMonacoCursorPositionByName(name: string) {
181+
private updateMonacoCursorPositionByName(name: string, fieldName?: string) {
156182
let declaration = findDeclarationByName(name, this.declarations);
157183
if (declaration === undefined) return;
158-
return this.updateMonacoCursorPositionByDeclaration(declaration);
184+
return this.updateMonacoCursorPositionByDeclaration(declaration, fieldName);
159185
}
160186

161187
@action
162188
private updateMonacoCursorPositionByDeclaration(
163189
declaration: ModuleDeclaration,
190+
fieldName?: string,
164191
) {
165192
if (
193+
fieldName &&
194+
'possibleFields' in declaration &&
195+
declaration.possibleFields
196+
) {
197+
let possibleFields = declaration.possibleFields;
198+
let field = possibleFields.get(fieldName);
199+
let loc =
200+
field?.path?.node && 'loc' in field.path.node && field.path.node.loc
201+
? field.path.node.loc
202+
: undefined;
203+
if (loc) {
204+
// Adjusts column to make cursor position right after the field name
205+
let fieldDecoratorTextLength = 8;
206+
let columnAdjustment = fieldDecoratorTextLength + fieldName.length;
207+
this.monacoService.updateCursorPosition(
208+
new Position(loc.start.line, loc.start.column + columnAdjustment),
209+
);
210+
}
211+
} else if (
166212
declaration.path?.node &&
167213
'body' in declaration.path.node &&
168214
'loc' in declaration.path.node.body &&

packages/host/app/components/operator-mode/code-submode.gts

+16-8
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import {
3636
isResolvedCodeRef,
3737
type ResolvedCodeRef,
3838
PermissionsContextName,
39+
CodeRef,
3940
} from '@cardstack/runtime-common';
4041
import { isEquivalentBodyPosition } from '@cardstack/runtime-common/schema-analysis-plugin';
4142

@@ -158,7 +159,9 @@ export default class CodeSubmode extends Component<Signature> {
158159

159160
private defaultPanelWidths: PanelWidths;
160161
private defaultPanelHeights: PanelHeights;
161-
private updateCursorByName: ((name: string) => void) | undefined;
162+
private updateCursorByName:
163+
| ((name: string, fieldName?: string) => void)
164+
| undefined;
162165
private panelSelections: Record<string, SelectedAccordionItem>;
163166

164167
private createFileModal: CreateFileModal | undefined;
@@ -497,10 +500,11 @@ export default class CodeSubmode extends Component<Signature> {
497500

498501
@action
499502
private goToDefinitionAndResetCursorPosition(
500-
codeRef: ResolvedCodeRef | undefined,
503+
codeRef: CodeRef | undefined,
501504
localName: string | undefined,
505+
fieldName?: string,
502506
) {
503-
this.goToDefinition(codeRef, localName);
507+
this.goToDefinition(codeRef, localName, fieldName);
504508
if (this.codePath) {
505509
let urlString = this.codePath.toString();
506510
this.recentFilesService.updateCursorPositionByURL(
@@ -512,14 +516,16 @@ export default class CodeSubmode extends Component<Signature> {
512516

513517
@action
514518
private goToDefinition(
515-
codeRef: ResolvedCodeRef | undefined,
519+
codeRef: CodeRef | undefined,
516520
localName: string | undefined,
521+
fieldName?: string,
517522
) {
518-
this.operatorModeStateService.updateCodePathWithCodeSelection(
523+
this.operatorModeStateService.updateCodePathWithSelection({
519524
codeRef,
520525
localName,
521-
this.updateCursorByName,
522-
);
526+
fieldName,
527+
onLocalSelection: this.updateCursorByName,
528+
});
523529
}
524530

525531
private loadScopedCSS = restartableTask(async () => {
@@ -713,7 +719,9 @@ export default class CodeSubmode extends Component<Signature> {
713719
this.createFileModal = createFileModal;
714720
};
715721

716-
private setupCodeEditor = (updateCursorByName: (name: string) => void) => {
722+
private setupCodeEditor = (
723+
updateCursorByName: (name: string, fieldName?: string) => void,
724+
) => {
717725
this.updateCursorByName = updateCursorByName;
718726
};
719727

packages/host/app/components/operator-mode/code-submode/schema-editor.gts

+3-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import Component from '@glimmer/component';
55
import { cached } from '@glimmer/tracking';
66

77
import { getPlural } from '@cardstack/runtime-common';
8-
import { type ResolvedCodeRef } from '@cardstack/runtime-common/code-ref';
8+
import { type CodeRef } from '@cardstack/runtime-common/code-ref';
99

1010
import { ModuleSyntax } from '@cardstack/runtime-common/module-syntax';
1111

@@ -30,8 +30,9 @@ interface Signature {
3030
card: typeof BaseDef;
3131
isReadOnly: boolean;
3232
goToDefinition: (
33-
codeRef: ResolvedCodeRef | undefined,
33+
codeRef: CodeRef | undefined,
3434
localName: string | undefined,
35+
fieldName?: string,
3536
) => void;
3637
};
3738
Blocks: {

0 commit comments

Comments
 (0)