@theseam/ui-common 1.0.2-beta.74 → 1.0.2-beta.83
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ai/index.d.ts +83 -16
- package/fesm2022/theseam-ui-common-ai.mjs +95 -49
- package/fesm2022/theseam-ui-common-ai.mjs.map +1 -1
- package/fesm2022/theseam-ui-common-graphql.mjs +93 -43
- package/fesm2022/theseam-ui-common-graphql.mjs.map +1 -1
- package/graphql/index.d.ts +27 -2
- package/package.json +1 -1
package/ai/index.d.ts
CHANGED
|
@@ -1,36 +1,103 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
2
|
import { AfterViewInit, InjectionToken, Type } from '@angular/core';
|
|
3
|
+
import { TheSeamDatatableColumn, DatatableComponent, ColumnsAlterationState } from '@theseam/ui-common/datatable';
|
|
4
|
+
import { DatatableGraphQLQueryRef } from '@theseam/ui-common/graphql';
|
|
3
5
|
import { BehaviorSubject, Observable } from 'rxjs';
|
|
4
6
|
import * as _angular_cdk_testing from '@angular/cdk/testing';
|
|
5
7
|
import { ComponentHarness } from '@angular/cdk/testing';
|
|
6
8
|
import { FormGroup, FormControl } from '@angular/forms';
|
|
7
|
-
import { DatatableComponent, ColumnsAlterationState } from '@theseam/ui-common/datatable';
|
|
8
9
|
import { AlterationDisplayItem } from '@theseam/ui-common/datatable-alterations-display';
|
|
9
10
|
|
|
11
|
+
/**
|
|
12
|
+
* Implemented by components that contribute "what the user is currently looking at"
|
|
13
|
+
* to the AI chat assistant. Instances are registered with `TheSeamChatContextRegistry`
|
|
14
|
+
* (see chat-context-registry.service.ts) and read at chat-send time.
|
|
15
|
+
*
|
|
16
|
+
* `getContext()` returning null/undefined means "I have nothing useful to contribute
|
|
17
|
+
* right now"; the registry drops that entry from the snapshot.
|
|
18
|
+
*/
|
|
19
|
+
interface TheSeamChatContext {
|
|
20
|
+
/** Discriminator — used by the backend formatter table. e.g. 'datatable', 'modal'. */
|
|
21
|
+
readonly type: string;
|
|
22
|
+
/** When true, this context is included even while a 'modal'-typed context is registered. Default false. */
|
|
23
|
+
readonly alwaysVisible?: boolean;
|
|
24
|
+
getContext(): unknown | Promise<unknown>;
|
|
25
|
+
}
|
|
26
|
+
/** Wire-shape of one context entry sent to the backend. */
|
|
27
|
+
interface TheSeamChatContextPayload {
|
|
28
|
+
type: string;
|
|
29
|
+
data: unknown;
|
|
30
|
+
}
|
|
31
|
+
|
|
10
32
|
interface ChatMessage {
|
|
11
|
-
role: '
|
|
33
|
+
role: 'user' | 'assistant';
|
|
12
34
|
content: string;
|
|
13
35
|
}
|
|
14
36
|
interface ChatResponse {
|
|
15
37
|
content: string;
|
|
16
38
|
}
|
|
17
|
-
interface
|
|
18
|
-
|
|
39
|
+
interface TheSeamAiChatRequest {
|
|
40
|
+
messages: ChatMessage[];
|
|
41
|
+
contexts?: TheSeamChatContextPayload[];
|
|
42
|
+
}
|
|
43
|
+
interface TheSeamAiProvider {
|
|
44
|
+
chat(request: TheSeamAiChatRequest): Promise<ChatResponse>;
|
|
19
45
|
}
|
|
20
46
|
|
|
21
|
-
declare class LmStudioAiProvider implements
|
|
22
|
-
chat(
|
|
47
|
+
declare class LmStudioAiProvider implements TheSeamAiProvider {
|
|
48
|
+
chat(request: TheSeamAiChatRequest): Promise<ChatResponse>;
|
|
23
49
|
}
|
|
24
50
|
|
|
25
|
-
declare class OpenRouterAiProvider implements
|
|
26
|
-
chat(
|
|
51
|
+
declare class OpenRouterAiProvider implements TheSeamAiProvider {
|
|
52
|
+
chat(request: TheSeamAiChatRequest): Promise<ChatResponse>;
|
|
27
53
|
}
|
|
28
54
|
|
|
29
55
|
type MockResponse = string | ((messages: ChatMessage[]) => string);
|
|
30
|
-
declare class MockAiProvider implements
|
|
56
|
+
declare class MockAiProvider implements TheSeamAiProvider {
|
|
31
57
|
private readonly _response;
|
|
32
58
|
constructor(_response?: MockResponse);
|
|
33
|
-
chat(
|
|
59
|
+
chat(request: TheSeamAiChatRequest): Promise<ChatResponse>;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
declare class TheSeamChatContextRegistry {
|
|
63
|
+
private readonly _contexts;
|
|
64
|
+
/**
|
|
65
|
+
* Register a context. Returns an unregister function — pair it with DestroyRef:
|
|
66
|
+
* inject(DestroyRef).onDestroy(registry.register(ctx))
|
|
67
|
+
*/
|
|
68
|
+
register(ctx: TheSeamChatContext): () => void;
|
|
69
|
+
unregister(ctx: TheSeamChatContext): void;
|
|
70
|
+
/**
|
|
71
|
+
* Resolve registered contexts to a wire-ready payload list. Applies the modal-mask
|
|
72
|
+
* rule (a `modal`-typed context hides others unless they set `alwaysVisible`) and
|
|
73
|
+
* drops entries whose `getContext()` returns null/undefined.
|
|
74
|
+
*/
|
|
75
|
+
snapshot(): Promise<TheSeamChatContextPayload[]>;
|
|
76
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<TheSeamChatContextRegistry, never>;
|
|
77
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<TheSeamChatContextRegistry>;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
interface TheSeamDatatableChatContextOptions {
|
|
81
|
+
/** Optional human label, e.g. 'Bales'. Helps the LLM disambiguate when multiple datatables are registered. */
|
|
82
|
+
label?: string;
|
|
83
|
+
}
|
|
84
|
+
interface TheSeamDatatableChatContextData {
|
|
85
|
+
label?: string;
|
|
86
|
+
operationName: string;
|
|
87
|
+
query: string;
|
|
88
|
+
variables: Record<string, unknown>;
|
|
89
|
+
columns: {
|
|
90
|
+
prop: string | number | undefined;
|
|
91
|
+
name: string | undefined;
|
|
92
|
+
}[];
|
|
93
|
+
}
|
|
94
|
+
declare class TheSeamDatatableChatContext implements TheSeamChatContext {
|
|
95
|
+
private readonly _queryRef;
|
|
96
|
+
private readonly _columns;
|
|
97
|
+
private readonly _options;
|
|
98
|
+
readonly type = "datatable";
|
|
99
|
+
constructor(_queryRef: DatatableGraphQLQueryRef<any, any, any>, _columns: readonly TheSeamDatatableColumn[], _options?: TheSeamDatatableChatContextOptions);
|
|
100
|
+
getContext(): TheSeamDatatableChatContextData | null;
|
|
34
101
|
}
|
|
35
102
|
|
|
36
103
|
type ChatContentSegment = {
|
|
@@ -56,9 +123,9 @@ interface ChatMessageDisplayModel {
|
|
|
56
123
|
|
|
57
124
|
declare class TheSeamChatComponent implements AfterViewInit {
|
|
58
125
|
private readonly _provider;
|
|
126
|
+
private readonly _chatContextRegistry;
|
|
59
127
|
private readonly _cdr;
|
|
60
128
|
private readonly _ngZone;
|
|
61
|
-
systemPrompt: string;
|
|
62
129
|
placeholder: string;
|
|
63
130
|
private _messageList?;
|
|
64
131
|
private _messageListScrollbar?;
|
|
@@ -74,10 +141,10 @@ declare class TheSeamChatComponent implements AfterViewInit {
|
|
|
74
141
|
private _maybeScrollToBottom;
|
|
75
142
|
private _scrollToBottom;
|
|
76
143
|
static ɵfac: i0.ɵɵFactoryDeclaration<TheSeamChatComponent, never>;
|
|
77
|
-
static ɵcmp: i0.ɵɵComponentDeclaration<TheSeamChatComponent, "seam-chat", never, { "
|
|
144
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<TheSeamChatComponent, "seam-chat", never, { "placeholder": { "alias": "placeholder"; "required": false; }; }, {}, never, never, true, never>;
|
|
78
145
|
}
|
|
79
146
|
|
|
80
|
-
declare const THESEAM_CHAT_PROVIDER: InjectionToken<
|
|
147
|
+
declare const THESEAM_CHAT_PROVIDER: InjectionToken<TheSeamAiProvider>;
|
|
81
148
|
|
|
82
149
|
type ChatBlockRegistry = Map<string, Type<unknown>>;
|
|
83
150
|
declare const THESEAM_CHAT_BLOCK_REGISTRY: InjectionToken<ChatBlockRegistry>;
|
|
@@ -109,7 +176,7 @@ declare const getUserPrompt: (columns: any[], request: string) => string;
|
|
|
109
176
|
declare function parseResponse(responseContent: string, responseFormat: {
|
|
110
177
|
type: string;
|
|
111
178
|
} | undefined): any;
|
|
112
|
-
declare const THESEAM_DATATABLE_PROMPTER_PROVIDER: InjectionToken<
|
|
179
|
+
declare const THESEAM_DATATABLE_PROMPTER_PROVIDER: InjectionToken<TheSeamAiProvider>;
|
|
113
180
|
|
|
114
181
|
declare class TheSeamDatatablePrompterComponent {
|
|
115
182
|
private readonly _prefsAccessor;
|
|
@@ -140,5 +207,5 @@ declare class TheSeamDatatablePrompterComponent {
|
|
|
140
207
|
static ɵcmp: i0.ɵɵComponentDeclaration<TheSeamDatatablePrompterComponent, "seam-datatable-prompter", never, { "diffMode": { "alias": "diffMode"; "required": false; }; "compact": { "alias": "compact"; "required": false; }; "prompt": { "alias": "prompt"; "required": false; }; "datatable": { "alias": "datatable"; "required": false; }; "showAlts": { "alias": "showAlts"; "required": false; }; }, {}, never, never, true, never>;
|
|
141
208
|
}
|
|
142
209
|
|
|
143
|
-
export { LmStudioAiProvider, MockAiProvider, OpenRouterAiProvider, THESEAM_CHAT_BLOCK_REGISTRY, THESEAM_CHAT_PROVIDER, THESEAM_DATATABLE_PROMPTER_PROVIDER, TheSeamChatComponent, TheSeamChatHarness, TheSeamDatatablePrompterComponent, assistantPrompt, getUserPrompt, parseChatResponse, parseResponse };
|
|
144
|
-
export type {
|
|
210
|
+
export { LmStudioAiProvider, MockAiProvider, OpenRouterAiProvider, THESEAM_CHAT_BLOCK_REGISTRY, THESEAM_CHAT_PROVIDER, THESEAM_DATATABLE_PROMPTER_PROVIDER, TheSeamChatComponent, TheSeamChatContextRegistry, TheSeamChatHarness, TheSeamDatatableChatContext, TheSeamDatatablePrompterComponent, assistantPrompt, getUserPrompt, parseChatResponse, parseResponse };
|
|
211
|
+
export type { ChatBlockRegistry, ChatContentSegment, ChatMessage, ChatResponse, TheSeamAiChatRequest, TheSeamAiProvider, TheSeamChatContext, TheSeamChatContextPayload, TheSeamDatatableChatContextData, TheSeamDatatableChatContextOptions };
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { InjectionToken, inject, Injector, Input, ChangeDetectionStrategy, Component, EventEmitter, Output, ChangeDetectorRef, NgZone, ViewChild } from '@angular/core';
|
|
2
|
+
import { Injectable, InjectionToken, inject, Injector, Input, ChangeDetectionStrategy, Component, EventEmitter, Output, ChangeDetectorRef, NgZone, ViewChild } from '@angular/core';
|
|
3
|
+
import { print } from 'graphql';
|
|
4
|
+
import { processGql } from '@theseam/ui-common/graphql';
|
|
3
5
|
import { NgForOf, NgIf, NgComponentOutlet, AsyncPipe, JsonPipe } from '@angular/common';
|
|
4
6
|
import { BehaviorSubject, switchMap, of, startWith, map, shareReplay } from 'rxjs';
|
|
5
7
|
import { TheSeamOverlayScrollbarDirective } from '@theseam/ui-common/scrollbar';
|
|
@@ -19,7 +21,7 @@ import { TheSeamLoadingModule } from '@theseam/ui-common/loading';
|
|
|
19
21
|
import { AlterationsDiffComponent } from '@theseam/ui-common/datatable-alterations-display';
|
|
20
22
|
|
|
21
23
|
class LmStudioAiProvider {
|
|
22
|
-
async chat(
|
|
24
|
+
async chat(request) {
|
|
23
25
|
const url = 'http://localhost:1234/v1/chat/completions';
|
|
24
26
|
const headers = {
|
|
25
27
|
'Content-Type': 'application/json',
|
|
@@ -30,19 +32,20 @@ class LmStudioAiProvider {
|
|
|
30
32
|
headers,
|
|
31
33
|
body: JSON.stringify({
|
|
32
34
|
model,
|
|
33
|
-
messages: messages.map((m) => ({
|
|
35
|
+
messages: request.messages.map((m) => ({
|
|
36
|
+
role: m.role,
|
|
37
|
+
content: m.content,
|
|
38
|
+
})),
|
|
34
39
|
}),
|
|
35
40
|
});
|
|
36
41
|
const data = await response.json();
|
|
37
|
-
console.log('Response from AI:', data);
|
|
38
42
|
const content = data.choices[0].message.content;
|
|
39
|
-
console.log(`%cResponse from AI. content:\n${content}`, 'color: limegreen;');
|
|
40
43
|
return { content };
|
|
41
44
|
}
|
|
42
45
|
}
|
|
43
46
|
|
|
44
47
|
class OpenRouterAiProvider {
|
|
45
|
-
async chat(
|
|
48
|
+
async chat(request) {
|
|
46
49
|
const defaultApiKey = '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';
|
|
47
50
|
const url = 'https://openrouter.ai/api/v1/chat/completions';
|
|
48
51
|
const apiKey = localStorage.getItem('openrouter-api-key') || defaultApiKey;
|
|
@@ -56,14 +59,15 @@ class OpenRouterAiProvider {
|
|
|
56
59
|
headers,
|
|
57
60
|
body: JSON.stringify({
|
|
58
61
|
model,
|
|
59
|
-
messages: messages.map((m) => ({
|
|
62
|
+
messages: request.messages.map((m) => ({
|
|
63
|
+
role: m.role,
|
|
64
|
+
content: m.content,
|
|
65
|
+
})),
|
|
60
66
|
response_format: { type: 'json_object' },
|
|
61
67
|
}),
|
|
62
68
|
});
|
|
63
69
|
const data = await response.json();
|
|
64
|
-
console.log('Response from AI:', data);
|
|
65
70
|
const content = data.choices[0].message.content;
|
|
66
|
-
console.log(`%cResponse from AI. content:\n${content}`, 'color: limegreen;');
|
|
67
71
|
return { content };
|
|
68
72
|
}
|
|
69
73
|
}
|
|
@@ -73,14 +77,75 @@ class MockAiProvider {
|
|
|
73
77
|
constructor(_response = 'Mock response') {
|
|
74
78
|
this._response = _response;
|
|
75
79
|
}
|
|
76
|
-
async chat(
|
|
80
|
+
async chat(request) {
|
|
77
81
|
const content = typeof this._response === 'function'
|
|
78
|
-
? this._response(messages)
|
|
82
|
+
? this._response(request.messages)
|
|
79
83
|
: this._response;
|
|
80
84
|
return { content };
|
|
81
85
|
}
|
|
82
86
|
}
|
|
83
87
|
|
|
88
|
+
class TheSeamChatContextRegistry {
|
|
89
|
+
_contexts = new Set();
|
|
90
|
+
/**
|
|
91
|
+
* Register a context. Returns an unregister function — pair it with DestroyRef:
|
|
92
|
+
* inject(DestroyRef).onDestroy(registry.register(ctx))
|
|
93
|
+
*/
|
|
94
|
+
register(ctx) {
|
|
95
|
+
this._contexts.add(ctx);
|
|
96
|
+
return () => this._contexts.delete(ctx);
|
|
97
|
+
}
|
|
98
|
+
unregister(ctx) {
|
|
99
|
+
this._contexts.delete(ctx);
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Resolve registered contexts to a wire-ready payload list. Applies the modal-mask
|
|
103
|
+
* rule (a `modal`-typed context hides others unless they set `alwaysVisible`) and
|
|
104
|
+
* drops entries whose `getContext()` returns null/undefined.
|
|
105
|
+
*/
|
|
106
|
+
async snapshot() {
|
|
107
|
+
const all = [...this._contexts];
|
|
108
|
+
const masked = all.some((c) => c.type === 'modal');
|
|
109
|
+
const visible = masked
|
|
110
|
+
? all.filter((c) => c.type === 'modal' || c.alwaysVisible)
|
|
111
|
+
: all;
|
|
112
|
+
const resolved = await Promise.all(visible.map(async (c) => ({ type: c.type, data: await c.getContext() })));
|
|
113
|
+
return resolved.filter((p) => p.data != null);
|
|
114
|
+
}
|
|
115
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TheSeamChatContextRegistry, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
116
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TheSeamChatContextRegistry, providedIn: 'root' });
|
|
117
|
+
}
|
|
118
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TheSeamChatContextRegistry, decorators: [{
|
|
119
|
+
type: Injectable,
|
|
120
|
+
args: [{ providedIn: 'root' }]
|
|
121
|
+
}] });
|
|
122
|
+
|
|
123
|
+
class TheSeamDatatableChatContext {
|
|
124
|
+
_queryRef;
|
|
125
|
+
_columns;
|
|
126
|
+
_options;
|
|
127
|
+
type = 'datatable';
|
|
128
|
+
constructor(_queryRef, _columns, _options = {}) {
|
|
129
|
+
this._queryRef = _queryRef;
|
|
130
|
+
this._columns = _columns;
|
|
131
|
+
this._options = _options;
|
|
132
|
+
}
|
|
133
|
+
getContext() {
|
|
134
|
+
const opts = this._queryRef.getOptions();
|
|
135
|
+
if (!opts)
|
|
136
|
+
return null;
|
|
137
|
+
const { query, variables } = processGql(opts.query, this._queryRef.getVariables(), this._queryRef.getQueryProcessingConfig() ?? { variables: {} });
|
|
138
|
+
const operationName = query.definitions.find((d) => d.kind === 'OperationDefinition')?.name?.value ?? '';
|
|
139
|
+
return {
|
|
140
|
+
label: this._options.label,
|
|
141
|
+
operationName,
|
|
142
|
+
query: print(query),
|
|
143
|
+
variables,
|
|
144
|
+
columns: this._columns.map((c) => ({ prop: c.prop, name: c.name })),
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
84
149
|
const THESEAM_CHAT_PROVIDER = new InjectionToken('TheSeamChatProvider');
|
|
85
150
|
|
|
86
151
|
/**
|
|
@@ -309,9 +374,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
|
|
|
309
374
|
|
|
310
375
|
class TheSeamChatComponent {
|
|
311
376
|
_provider = inject(THESEAM_CHAT_PROVIDER, { optional: true });
|
|
377
|
+
_chatContextRegistry = inject(TheSeamChatContextRegistry, {
|
|
378
|
+
optional: true,
|
|
379
|
+
});
|
|
312
380
|
_cdr = inject(ChangeDetectorRef);
|
|
313
381
|
_ngZone = inject(NgZone);
|
|
314
|
-
systemPrompt = '';
|
|
315
382
|
placeholder = 'Type a message...';
|
|
316
383
|
_messageList;
|
|
317
384
|
_messageListScrollbar;
|
|
@@ -319,32 +386,18 @@ class TheSeamChatComponent {
|
|
|
319
386
|
_messages = [];
|
|
320
387
|
_displayMessages = [];
|
|
321
388
|
// Pixels of slack allowed when deciding if the viewport is "at the bottom".
|
|
322
|
-
// Small enough that scrolling up a line unpins, but forgiving of sub-pixel drift.
|
|
323
389
|
_pinnedThreshold = 32;
|
|
324
|
-
// True when the viewport is (or should be) tracking the latest content. Starts
|
|
325
|
-
// true so the first messages scroll into view. Updated on every scroll event.
|
|
326
390
|
_isPinnedToBottom = true;
|
|
327
|
-
// Set when a user action (e.g. sending a message) requires the view to jump
|
|
328
|
-
// to the bottom on the next content-size change, regardless of pinned state.
|
|
329
|
-
// Cleared as soon as it's consumed.
|
|
330
391
|
_forceScrollOnNextResize = false;
|
|
331
392
|
ngAfterViewInit() {
|
|
332
393
|
const scrollInstance = this._messageListScrollbar?.instance;
|
|
333
394
|
if (!scrollInstance) {
|
|
334
395
|
return;
|
|
335
396
|
}
|
|
336
|
-
// OverlayScrollbars callbacks run outside Angular already (the directive's
|
|
337
|
-
// service initializes with runOutsideAngular). These handlers only update
|
|
338
|
-
// local flags and call scroll() — no change detection needed.
|
|
339
397
|
this._ngZone.runOutsideAngular(() => {
|
|
340
398
|
scrollInstance.options({
|
|
341
399
|
callbacks: {
|
|
342
400
|
onScroll: () => this._updatePinnedState(),
|
|
343
|
-
// Fires when the content's scrollable size changes: a new message
|
|
344
|
-
// appended, a custom block finishing its async render, an image
|
|
345
|
-
// finishing loading, etc. This removes the need for a setTimeout
|
|
346
|
-
// hack because we react to actual size changes rather than guessing
|
|
347
|
-
// when rendering has settled.
|
|
348
401
|
onContentSizeChanged: () => this._maybeScrollToBottom(),
|
|
349
402
|
},
|
|
350
403
|
});
|
|
@@ -367,18 +420,15 @@ class TheSeamChatComponent {
|
|
|
367
420
|
timestamp: new Date(),
|
|
368
421
|
},
|
|
369
422
|
];
|
|
370
|
-
// The user just sent a message — jump to the bottom even if they had
|
|
371
|
-
// scrolled up previously. Consumed by the next onContentSizeChanged.
|
|
372
423
|
this._forceScrollOnNextResize = true;
|
|
373
424
|
this._cdr.markForCheck();
|
|
374
425
|
this._loadingSubject.next(true);
|
|
375
426
|
try {
|
|
376
|
-
const
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
const response = await this._provider.chat(messagesToSend);
|
|
427
|
+
const contexts = (await this._chatContextRegistry?.snapshot()) ?? [];
|
|
428
|
+
const response = await this._provider.chat({
|
|
429
|
+
messages: this._messages,
|
|
430
|
+
contexts: contexts.length === 0 ? undefined : contexts,
|
|
431
|
+
});
|
|
382
432
|
const assistantMessage = {
|
|
383
433
|
role: 'assistant',
|
|
384
434
|
content: response.content,
|
|
@@ -411,12 +461,6 @@ class TheSeamChatComponent {
|
|
|
411
461
|
info.position.y >= info.max.y - this._pinnedThreshold;
|
|
412
462
|
}
|
|
413
463
|
_maybeScrollToBottom() {
|
|
414
|
-
// Auto-scroll only when the user expects it:
|
|
415
|
-
// - They just sent a message (forceScroll), OR
|
|
416
|
-
// - They were already following the latest content (pinnedToBottom).
|
|
417
|
-
// If they scrolled up to read an earlier message, we leave their viewport
|
|
418
|
-
// alone so continued content growth (e.g. a streaming answer or an
|
|
419
|
-
// async-rendered block) doesn't keep yanking it back.
|
|
420
464
|
if (this._forceScrollOnNextResize || this._isPinnedToBottom) {
|
|
421
465
|
this._scrollToBottom();
|
|
422
466
|
this._forceScrollOnNextResize = false;
|
|
@@ -430,7 +474,7 @@ class TheSeamChatComponent {
|
|
|
430
474
|
}
|
|
431
475
|
}
|
|
432
476
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TheSeamChatComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
433
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: TheSeamChatComponent, isStandalone: true, selector: "seam-chat", inputs: {
|
|
477
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: TheSeamChatComponent, isStandalone: true, selector: "seam-chat", inputs: { placeholder: "placeholder" }, viewQueries: [{ propertyName: "_messageList", first: true, predicate: ["messageList"], descendants: true }, { propertyName: "_messageListScrollbar", first: true, predicate: TheSeamOverlayScrollbarDirective, descendants: true }], ngImport: i0, template: "<div class=\"seam-chat\">\n <div class=\"seam-chat__messages\" #messageList seamOverlayScrollbar>\n <seam-chat-message\n *ngFor=\"let msg of _displayMessages\"\n [message]=\"msg\"\n ></seam-chat-message>\n\n <div *ngIf=\"_loadingSubject | async\" class=\"seam-chat__loading\">\n <span>Thinking...</span>\n </div>\n </div>\n\n <seam-chat-input\n [placeholder]=\"placeholder\"\n [disabled]=\"!!(_loadingSubject | async)\"\n (messageSent)=\"_onMessageSent($event)\"\n ></seam-chat-input>\n</div>\n", styles: [":host{display:flex;flex-direction:column;height:100%;overflow:hidden}.seam-chat{display:flex;flex-direction:column;height:100%;overflow:hidden}.seam-chat__messages{flex:1;overflow-y:auto;padding:12px}.seam-chat__loading{padding:8px 12px;color:#6c757d;font-style:italic}\n"], dependencies: [{ kind: "directive", type: NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: SeamChatMessageComponent, selector: "seam-chat-message", inputs: ["message"] }, { kind: "component", type: SeamChatInputComponent, selector: "seam-chat-input", inputs: ["placeholder", "disabled"], outputs: ["messageSent"] }, { kind: "directive", type: TheSeamOverlayScrollbarDirective, selector: "[seamOverlayScrollbar]", inputs: ["seamOverlayScrollbar", "overlayScrollbarEnabled"], exportAs: ["seamOverlayScrollbar"] }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
434
478
|
}
|
|
435
479
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TheSeamChatComponent, decorators: [{
|
|
436
480
|
type: Component,
|
|
@@ -442,9 +486,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
|
|
|
442
486
|
SeamChatInputComponent,
|
|
443
487
|
TheSeamOverlayScrollbarDirective,
|
|
444
488
|
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"seam-chat\">\n <div class=\"seam-chat__messages\" #messageList seamOverlayScrollbar>\n <seam-chat-message\n *ngFor=\"let msg of _displayMessages\"\n [message]=\"msg\"\n ></seam-chat-message>\n\n <div *ngIf=\"_loadingSubject | async\" class=\"seam-chat__loading\">\n <span>Thinking...</span>\n </div>\n </div>\n\n <seam-chat-input\n [placeholder]=\"placeholder\"\n [disabled]=\"!!(_loadingSubject | async)\"\n (messageSent)=\"_onMessageSent($event)\"\n ></seam-chat-input>\n</div>\n", styles: [":host{display:flex;flex-direction:column;height:100%;overflow:hidden}.seam-chat{display:flex;flex-direction:column;height:100%;overflow:hidden}.seam-chat__messages{flex:1;overflow-y:auto;padding:12px}.seam-chat__loading{padding:8px 12px;color:#6c757d;font-style:italic}\n"] }]
|
|
445
|
-
}], propDecorators: {
|
|
446
|
-
type: Input
|
|
447
|
-
}], placeholder: [{
|
|
489
|
+
}], propDecorators: { placeholder: [{
|
|
448
490
|
type: Input
|
|
449
491
|
}], _messageList: [{
|
|
450
492
|
type: ViewChild,
|
|
@@ -895,10 +937,14 @@ class TheSeamDatatablePrompterComponent {
|
|
|
895
937
|
return;
|
|
896
938
|
}
|
|
897
939
|
this._aiProvider
|
|
898
|
-
.chat(
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
940
|
+
.chat({
|
|
941
|
+
messages: [
|
|
942
|
+
{
|
|
943
|
+
role: 'user',
|
|
944
|
+
content: `${assistantPrompt}\n\n---\n\n${userPrompt}`,
|
|
945
|
+
},
|
|
946
|
+
],
|
|
947
|
+
})
|
|
902
948
|
.then(async (response) => {
|
|
903
949
|
const alterations = parseResponse(response.content, undefined);
|
|
904
950
|
// this._form.reset()
|
|
@@ -993,5 +1039,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
|
|
|
993
1039
|
* Generated bundle index. Do not edit.
|
|
994
1040
|
*/
|
|
995
1041
|
|
|
996
|
-
export { LmStudioAiProvider, MockAiProvider, OpenRouterAiProvider, THESEAM_CHAT_BLOCK_REGISTRY, THESEAM_CHAT_PROVIDER, THESEAM_DATATABLE_PROMPTER_PROVIDER, TheSeamChatComponent, TheSeamChatHarness, TheSeamDatatablePrompterComponent, assistantPrompt, getUserPrompt, parseChatResponse, parseResponse };
|
|
1042
|
+
export { LmStudioAiProvider, MockAiProvider, OpenRouterAiProvider, THESEAM_CHAT_BLOCK_REGISTRY, THESEAM_CHAT_PROVIDER, THESEAM_DATATABLE_PROMPTER_PROVIDER, TheSeamChatComponent, TheSeamChatContextRegistry, TheSeamChatHarness, TheSeamDatatableChatContext, TheSeamDatatablePrompterComponent, assistantPrompt, getUserPrompt, parseChatResponse, parseResponse };
|
|
997
1043
|
//# sourceMappingURL=theseam-ui-common-ai.mjs.map
|