@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 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: 'system' | 'user' | 'assistant';
33
+ role: 'user' | 'assistant';
12
34
  content: string;
13
35
  }
14
36
  interface ChatResponse {
15
37
  content: string;
16
38
  }
17
- interface AiProvider {
18
- chat(messages: ChatMessage[]): Promise<ChatResponse>;
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 AiProvider {
22
- chat(messages: ChatMessage[]): Promise<ChatResponse>;
47
+ declare class LmStudioAiProvider implements TheSeamAiProvider {
48
+ chat(request: TheSeamAiChatRequest): Promise<ChatResponse>;
23
49
  }
24
50
 
25
- declare class OpenRouterAiProvider implements AiProvider {
26
- chat(messages: ChatMessage[]): Promise<ChatResponse>;
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 AiProvider {
56
+ declare class MockAiProvider implements TheSeamAiProvider {
31
57
  private readonly _response;
32
58
  constructor(_response?: MockResponse);
33
- chat(messages: ChatMessage[]): Promise<ChatResponse>;
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, { "systemPrompt": { "alias": "systemPrompt"; "required": false; }; "placeholder": { "alias": "placeholder"; "required": false; }; }, {}, never, never, true, 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<AiProvider>;
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<AiProvider>;
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 { AiProvider, ChatBlockRegistry, ChatContentSegment, ChatMessage, ChatResponse };
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(messages) {
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) => ({ role: m.role, content: m.content })),
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(messages) {
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) => ({ role: m.role, content: m.content })),
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(messages) {
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 messagesToSend = [];
377
- if (this.systemPrompt) {
378
- messagesToSend.push({ role: 'system', content: this.systemPrompt });
379
- }
380
- messagesToSend.push(...this._messages);
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: { systemPrompt: "systemPrompt", 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 });
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: { systemPrompt: [{
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
- { role: 'system', content: assistantPrompt },
900
- { role: 'user', content: userPrompt },
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