jupyter-chat-components 0.1.3 → 0.3.0

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/README.md CHANGED
@@ -2,7 +2,37 @@
2
2
 
3
3
  [![Github Actions Status](https://github.com/brichet/jupyter-chat-components/workflows/Build/badge.svg)](https://github.com/brichet/jupyter-chat-components/actions/workflows/build.yml)
4
4
 
5
- Components to displayed in jupyter chat
5
+ A library of React components designed for use in Jupyter chat interfaces, with a focus on AI-powered interactions. These components are intended to be integrated into JupyterLab extensions that provide chat functionality.
6
+
7
+ ## MIME renderer
8
+
9
+ Components are exposed through a custom MIME type: `application/vnd.jupyter.chat.components`.
10
+
11
+ This extension registers a MIME renderer factory with JupyterLab's render MIME registry. To display a component, produce output with the MIME type above, where:
12
+
13
+ - the **data** value is the component name (e.g. `"tool-call"`)
14
+ - the **metadata** contains the props to pass to the component
15
+
16
+ The MIME renderer looks up the component name in the factory's registry and renders the corresponding React component.
17
+
18
+ ## Component registry
19
+
20
+ The registry is available directly on the `IComponentsRendererFactory` token as the `registry` property. It maps component names to React components and exposes the following methods:
21
+
22
+ - `add(name, component)` — register a new React component under a unique name
23
+ - `get(name)` — retrieve a registered component by name
24
+ - `has(name)` — check whether a component is registered
25
+ - `getNames()` — list all registered component names
26
+
27
+ Other JupyterLab extensions can consume the `IComponentsRendererFactory` token and use `registry.add()` to register their own components, which will then be available for rendering via the MIME bundle.
28
+
29
+ ## Available components
30
+
31
+ ### `tool-call`
32
+
33
+ Renders an AI tool call, displaying the tool name, input arguments, and output in a structured and readable format. Useful for visualizing function calls made by AI assistants during a conversation.
34
+
35
+ More components are planned for future releases.
6
36
 
7
37
  ## Requirements
8
38
 
@@ -0,0 +1,3 @@
1
+ export * from './inline-diff';
2
+ export * from './message-queue';
3
+ export * from './tool-call';
@@ -0,0 +1,3 @@
1
+ export * from './inline-diff';
2
+ export * from './message-queue';
3
+ export * from './tool-call';
@@ -0,0 +1,13 @@
1
+ import { TranslationBundle } from '@jupyterlab/translation';
2
+ import * as React from 'react';
3
+ import { IInlineDiff, IInlineDiffMetadata } from '../token';
4
+ export interface IInlineDiffProps extends IInlineDiffMetadata {
5
+ trans?: TranslationBundle;
6
+ }
7
+ export declare function getDiffFilename(path: string): string;
8
+ export declare function getInlineDiffLabel(diff: IInlineDiff): string;
9
+ export declare function getInlineDiffTitle(diff: IInlineDiff): string;
10
+ /**
11
+ * React component for rendering one or more inline diffs.
12
+ */
13
+ export declare const InlineDiff: React.FC<IInlineDiffProps>;
@@ -0,0 +1,128 @@
1
+ import { PathExt } from '@jupyterlab/coreutils';
2
+ import { nullTranslator } from '@jupyterlab/translation';
3
+ import * as React from 'react';
4
+ import { structuredPatch } from 'diff';
5
+ /** Maximum number of rendered lines before truncation. */
6
+ const MAX_DIFF_LINES = 20;
7
+ export function getDiffFilename(path) {
8
+ return PathExt.basename(path);
9
+ }
10
+ function getNotebookCellLabel(target) {
11
+ if (typeof target.cellIndex === 'number') {
12
+ return `Cell ${target.cellIndex + 1}`;
13
+ }
14
+ if (target.cellId) {
15
+ return `Cell ${target.cellId}`;
16
+ }
17
+ return 'Notebook Cell';
18
+ }
19
+ function getInlineDiffPatchPath(diff) {
20
+ var _a;
21
+ const target = diff.target;
22
+ if (target.kind === 'file') {
23
+ return target.path;
24
+ }
25
+ return [target.notebookPath, (_a = target.cellId) !== null && _a !== void 0 ? _a : target.cellIndex]
26
+ .filter(value => value !== undefined && value !== '')
27
+ .join('#');
28
+ }
29
+ export function getInlineDiffLabel(diff) {
30
+ if (diff.label) {
31
+ return diff.label;
32
+ }
33
+ const target = diff.target;
34
+ if (target.kind === 'file') {
35
+ return getDiffFilename(target.path);
36
+ }
37
+ const notebookName = getDiffFilename(target.notebookPath);
38
+ const cellLabel = getNotebookCellLabel(target);
39
+ return [notebookName, cellLabel].join(' · ');
40
+ }
41
+ export function getInlineDiffTitle(diff) {
42
+ const target = diff.target;
43
+ if (target.kind === 'file') {
44
+ return target.path;
45
+ }
46
+ const cellLabel = getNotebookCellLabel(target);
47
+ const cellIdLabel = typeof target.cellIndex === 'number' && target.cellId
48
+ ? `Cell ID ${target.cellId}`
49
+ : null;
50
+ return [target.notebookPath, cellLabel, cellIdLabel]
51
+ .filter(part => part !== null && part !== undefined && part !== '')
52
+ .join(' · ');
53
+ }
54
+ function toLineInfo(type, text, key) {
55
+ switch (type) {
56
+ case 'added':
57
+ return {
58
+ cssClass: 'jp-mod-added',
59
+ prefix: '+',
60
+ text,
61
+ key
62
+ };
63
+ case 'removed':
64
+ return {
65
+ cssClass: 'jp-mod-removed',
66
+ prefix: '-',
67
+ text,
68
+ key
69
+ };
70
+ case 'context':
71
+ return {
72
+ cssClass: 'jp-mod-context',
73
+ prefix: ' ',
74
+ text,
75
+ key
76
+ };
77
+ }
78
+ }
79
+ function buildDiffLinesFromHunk(hunk, hunkIndex) {
80
+ return hunk.lines
81
+ .filter(line => !line.startsWith('\\'))
82
+ .map((line, lineIndex) => {
83
+ var _a;
84
+ const prefix = (_a = line[0]) !== null && _a !== void 0 ? _a : ' ';
85
+ const text = line.slice(1);
86
+ const key = `${hunkIndex}-${hunk.oldStart}-${hunk.newStart}-${lineIndex}`;
87
+ if (prefix === '+') {
88
+ return toLineInfo('added', text, key);
89
+ }
90
+ if (prefix === '-') {
91
+ return toLineInfo('removed', text, key);
92
+ }
93
+ return toLineInfo('context', text, key);
94
+ });
95
+ }
96
+ function buildDiffLines(diff) {
97
+ var _a;
98
+ const patchPath = getInlineDiffPatchPath(diff);
99
+ const patch = structuredPatch(patchPath, patchPath, (_a = diff.oldText) !== null && _a !== void 0 ? _a : '', diff.newText, undefined, undefined, { context: Infinity });
100
+ return patch.hunks.reduce((lines, hunk, index) => {
101
+ lines.push(...buildDiffLinesFromHunk(hunk, index));
102
+ return lines;
103
+ }, []);
104
+ }
105
+ function DiffBlock({ diff, trans }) {
106
+ const filename = getInlineDiffLabel(diff);
107
+ const title = getInlineDiffTitle(diff);
108
+ const [expanded, setExpanded] = React.useState(false);
109
+ const allLines = React.useMemo(() => buildDiffLines(diff), [diff]);
110
+ const canTruncate = allLines.length > MAX_DIFF_LINES;
111
+ const visibleLines = canTruncate && !expanded ? allLines.slice(0, MAX_DIFF_LINES) : allLines;
112
+ const hiddenCount = allLines.length - MAX_DIFF_LINES;
113
+ return (React.createElement("div", { className: "jp-ai-inline-diff-block" },
114
+ React.createElement("div", { className: "jp-ai-inline-diff-header", title: title }, filename),
115
+ React.createElement("div", { className: "jp-ai-inline-diff-content" },
116
+ visibleLines.length ? (visibleLines.map(line => (React.createElement("div", { key: line.key, className: `jp-ai-inline-diff-line ${line.cssClass}` },
117
+ React.createElement("span", { className: "jp-ai-inline-diff-line-prefix" }, line.prefix),
118
+ React.createElement("span", { className: "jp-ai-inline-diff-line-text" }, line.text))))) : (React.createElement("div", { className: "jp-ai-inline-diff-empty" }, trans.__('No changes'))),
119
+ canTruncate && !expanded && (React.createElement("button", { className: "jp-ai-inline-diff-toggle", onClick: () => setExpanded(true), type: "button" }, trans.__('... %1 more lines', hiddenCount))),
120
+ canTruncate && expanded && (React.createElement("button", { className: "jp-ai-inline-diff-toggle", onClick: () => setExpanded(false), type: "button" }, trans.__('Show less'))))));
121
+ }
122
+ /**
123
+ * React component for rendering one or more inline diffs.
124
+ */
125
+ export const InlineDiff = ({ diffs, trans }) => {
126
+ const transBundle = trans !== null && trans !== void 0 ? trans : nullTranslator.load('jupyterlab');
127
+ return (React.createElement("div", { className: "jp-ai-inline-diff-container" }, diffs.map((diff, index) => (React.createElement(DiffBlock, { key: `${getInlineDiffPatchPath(diff)}-${index}`, diff: diff, trans: transBundle })))));
128
+ };
@@ -0,0 +1,13 @@
1
+ import * as React from 'react';
2
+ import { IComponentProps, IMessageQueueMetadata, RemoveQueuedMessage } from '../token';
3
+ /**
4
+ * Props for the MessageQueue component.
5
+ */
6
+ export interface IMessageQueueProps extends IComponentProps, IMessageQueueMetadata {
7
+ removeQueuedMessage?: RemoveQueuedMessage;
8
+ }
9
+ /**
10
+ * React component that displays a list of queued messages by
11
+ * showing each pending message as a bubble in the chat
12
+ */
13
+ export declare const MessageQueue: React.FC<IMessageQueueProps>;
@@ -0,0 +1,13 @@
1
+ import * as React from 'react';
2
+ /**
3
+ * React component that displays a list of queued messages by
4
+ * showing each pending message as a bubble in the chat
5
+ */
6
+ export const MessageQueue = ({ messages, targetId, trans, removeQueuedMessage }) => {
7
+ if (!messages || messages.length === 0) {
8
+ return null;
9
+ }
10
+ return (React.createElement("div", { className: "jp-chat-message-queue" }, messages.map(msg => (React.createElement("div", { key: msg.id, className: "jp-chat-message-queue-bubble" },
11
+ React.createElement("span", { className: "jp-chat-message-queue-text" }, msg.body),
12
+ removeQueuedMessage && targetId && (React.createElement("button", { className: "jp-chat-message-queue-remove", onClick: () => removeQueuedMessage(targetId, msg.id), title: trans.__('Remove from queue'), type: "button" }, "\u2715")))))));
13
+ };
@@ -1,19 +1,28 @@
1
- import { TranslationBundle } from '@jupyterlab/translation';
2
1
  import * as React from 'react';
3
- import { IToolCallMetadata, ToolCallApproval } from '../token';
2
+ import { IComponentProps, ToolCallApproval } from '../token';
3
+ /**
4
+ * Tool call status types.
5
+ */
6
+ export type ToolCallStatus = 'pending' | 'awaiting_approval' | 'approved' | 'rejected' | 'completed' | 'error';
4
7
  /**
5
8
  * Options for building tool call HTML.
6
9
  */
7
- export interface IToolCallHtmlOptions extends IToolCallMetadata {
8
- trans: TranslationBundle;
9
- toolCallApproval: ToolCallApproval;
10
+ export interface IToolCallMetadata {
11
+ toolName: string;
12
+ input: string;
13
+ status: ToolCallStatus;
14
+ summary?: string;
15
+ output?: string;
16
+ targetId?: string;
17
+ approvalId?: string;
10
18
  }
11
- export declare function escapeHtml(value: string): string;
12
19
  /**
13
- * React component props for ToolCall.
20
+ * Options for building tool call HTML.
14
21
  */
15
- export interface IToolCallProps extends IToolCallHtmlOptions {
22
+ export interface IToolCallProps extends IComponentProps, IToolCallMetadata {
23
+ toolCallApproval?: ToolCallApproval;
16
24
  }
25
+ export declare function escapeHtml(value: string): string;
17
26
  /**
18
27
  * React functional component for displaying a tool call.
19
28
  *
@@ -71,6 +71,9 @@ export const ToolCall = ({ toolName, input, status, summary, output, targetId, a
71
71
  const config = STATUS_CONFIG[status];
72
72
  const statusText = getStatusText(status, trans);
73
73
  const resultLabel = status === 'error' ? trans.__('Error') : trans.__('Result');
74
+ if (status === 'awaiting_approval' && !toolCallApproval) {
75
+ console.error('The tool call has no approval function, approval, it will not work as expected');
76
+ }
74
77
  return (React.createElement("details", { className: `jp-ai-tool-call ${config.cssClass}`, open: config.open },
75
78
  React.createElement("summary", { className: "jp-ai-tool-header" },
76
79
  React.createElement("div", { className: "jp-ai-tool-icon" }, "\u26A1"),
package/lib/factory.d.ts CHANGED
@@ -1,7 +1,8 @@
1
1
  import { IRenderMime } from '@jupyterlab/rendermime-interfaces';
2
2
  import { ReactWidget } from '@jupyterlab/ui-components';
3
3
  import * as React from 'react';
4
- import { IComponentsRendererFactory, ToolCallApproval } from './token';
4
+ import { ComponentRegistry } from './registry';
5
+ import { IComponentRegistry, IComponentsRendererFactory, RemoveQueuedMessage, ToolCallApproval } from './token';
5
6
  type ReactRenderElement = Array<React.ReactElement<any>> | React.ReactElement<any>;
6
7
  /**
7
8
  * The options for the chat components renderer.
@@ -10,10 +11,18 @@ interface IComponentsRendererOptions extends IRenderMime.IRendererOptions {
10
11
  /**
11
12
  * The callback to approve or reject a tool.
12
13
  */
13
- toolCallApproval: ToolCallApproval;
14
+ toolCallApproval?: ToolCallApproval;
15
+ /**
16
+ * The callback to remove a queued message.
17
+ */
18
+ removeQueuedMessage?: RemoveQueuedMessage;
19
+ /**
20
+ * The component registry.
21
+ */
22
+ registry: IComponentRegistry;
14
23
  }
15
24
  /**
16
- * A widget for rendering .
25
+ * A widget for rendering components from mime bundle.
17
26
  */
18
27
  export declare class ComponentsRenderer extends ReactWidget implements IRenderMime.IRenderer {
19
28
  /**
@@ -27,7 +36,9 @@ export declare class ComponentsRenderer extends ReactWidget implements IRenderMi
27
36
  protected render(): ReactRenderElement | null;
28
37
  private _trans;
29
38
  private _mimeType;
30
- private _toolCallApproval;
39
+ private _toolCallApproval?;
40
+ private _removeQueuedMessage?;
41
+ private _registry;
31
42
  private _data;
32
43
  private _metadata;
33
44
  }
@@ -38,7 +49,10 @@ export declare class RendererFactory implements IComponentsRendererFactory {
38
49
  readonly safe = true;
39
50
  readonly mimeTypes: string[];
40
51
  readonly defaultRank = 100;
52
+ readonly registry: ComponentRegistry;
41
53
  toolCallApproval: ToolCallApproval;
54
+ removeQueuedMessage: RemoveQueuedMessage;
55
+ constructor();
42
56
  createRenderer: (options: IRenderMime.IRendererOptions) => ComponentsRenderer;
43
57
  }
44
58
  export {};
package/lib/factory.js CHANGED
@@ -1,7 +1,8 @@
1
1
  import { nullTranslator } from '@jupyterlab/translation';
2
2
  import { ReactWidget } from '@jupyterlab/ui-components';
3
3
  import * as React from 'react';
4
- import { ToolCall } from './components/tool-call';
4
+ import { InlineDiff, MessageQueue, ToolCall } from './components';
5
+ import { ComponentRegistry } from './registry';
5
6
  /**
6
7
  * The default mime type for the extension.
7
8
  */
@@ -11,7 +12,7 @@ const MIME_TYPE = 'application/vnd.jupyter.chat.components';
11
12
  */
12
13
  const CLASS_NAME = 'jp-RenderedChatComponents';
13
14
  /**
14
- * A widget for rendering .
15
+ * A widget for rendering components from mime bundle.
15
16
  */
16
17
  export class ComponentsRenderer extends ReactWidget {
17
18
  /**
@@ -25,26 +26,38 @@ export class ComponentsRenderer extends ReactWidget {
25
26
  this._trans = ((_a = options.translator) !== null && _a !== void 0 ? _a : nullTranslator).load('jupyterlab');
26
27
  this._mimeType = options.mimeType;
27
28
  this._toolCallApproval = options.toolCallApproval;
29
+ this._removeQueuedMessage = options.removeQueuedMessage;
30
+ this._registry = options.registry;
28
31
  this.addClass(CLASS_NAME);
29
32
  }
30
33
  /**
31
34
  * Render into this widget's node.
32
35
  */
33
36
  async renderModel(model) {
37
+ var _a;
34
38
  this._data = model.data[this._mimeType];
35
- this._metadata = { ...model.metadata };
39
+ const metadata = model.metadata;
40
+ this._metadata = (_a = metadata[this._mimeType]) !== null && _a !== void 0 ? _a : {
41
+ ...metadata
42
+ };
36
43
  return this.update();
37
44
  }
38
45
  render() {
46
+ if (!this._data) {
47
+ return null;
48
+ }
49
+ const Component = this._registry.get(this._data);
50
+ if (!Component) {
51
+ return null;
52
+ }
53
+ const componentsProps = { ...this._metadata };
39
54
  if (this._data === 'tool-call') {
40
- const toolCallOptions = {
41
- ...this._metadata,
42
- trans: this._trans,
43
- toolCallApproval: this._toolCallApproval
44
- };
45
- return React.createElement(ToolCall, { ...toolCallOptions });
55
+ componentsProps.toolCallApproval = this._toolCallApproval;
56
+ }
57
+ if (this._data === 'message-queue') {
58
+ componentsProps.removeQueuedMessage = this._removeQueuedMessage;
46
59
  }
47
- return null;
60
+ return React.createElement(Component, { ...componentsProps, trans: this._trans });
48
61
  }
49
62
  }
50
63
  /**
@@ -56,11 +69,18 @@ export class RendererFactory {
56
69
  this.mimeTypes = [MIME_TYPE];
57
70
  this.defaultRank = 100;
58
71
  this.toolCallApproval = null;
72
+ this.removeQueuedMessage = null;
59
73
  this.createRenderer = (options) => {
60
74
  return new ComponentsRenderer({
61
75
  ...options,
62
- toolCallApproval: this.toolCallApproval
76
+ toolCallApproval: this.toolCallApproval,
77
+ removeQueuedMessage: this.removeQueuedMessage,
78
+ registry: this.registry
63
79
  });
64
80
  };
81
+ this.registry = new ComponentRegistry();
82
+ this.registry.add('tool-call', ToolCall);
83
+ this.registry.add('inline-diff', InlineDiff);
84
+ this.registry.add('message-queue', MessageQueue);
65
85
  }
66
86
  }
package/lib/index.d.ts CHANGED
@@ -6,4 +6,6 @@ import { IComponentsRendererFactory } from './token';
6
6
  declare const factory: JupyterFrontEndPlugin<IComponentsRendererFactory>;
7
7
  export * from './token';
8
8
  export * from './factory';
9
+ export * from './registry';
10
+ export * from './components';
9
11
  export default factory;
package/lib/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
2
- import { IComponentsRendererFactory } from './token';
3
2
  import { RendererFactory } from './factory';
3
+ import { IComponentsRendererFactory } from './token';
4
4
  /**
5
5
  * The plugin providing the chat component renderer.
6
6
  */
@@ -18,4 +18,6 @@ const factory = {
18
18
  };
19
19
  export * from './token';
20
20
  export * from './factory';
21
+ export * from './registry';
22
+ export * from './components';
21
23
  export default factory;
@@ -0,0 +1,35 @@
1
+ import * as React from 'react';
2
+ import { IComponentRegistry } from './token';
3
+ /**
4
+ * A registry for React components.
5
+ */
6
+ export declare class ComponentRegistry implements IComponentRegistry {
7
+ /**
8
+ * Register a React component.
9
+ *
10
+ * @param name - The unique name/identifier for the component
11
+ * @param component - The React component
12
+ */
13
+ add(name: string, component: React.ComponentType<any>): void;
14
+ /**
15
+ * Get a registered component by name.
16
+ *
17
+ * @param name - The name of the component
18
+ * @returns the React component, or undefined if not found
19
+ */
20
+ get(name: string): React.ComponentType<any> | undefined;
21
+ /**
22
+ * Check if a component is registered.
23
+ *
24
+ * @param name - The name of the component
25
+ * @returns whether the component is registered
26
+ */
27
+ has(name: string): boolean;
28
+ /**
29
+ * Get all registered component names.
30
+ *
31
+ * @returns the component names
32
+ */
33
+ getNames(): string[];
34
+ private _components;
35
+ }
@@ -0,0 +1,46 @@
1
+ /**
2
+ * A registry for React components.
3
+ */
4
+ export class ComponentRegistry {
5
+ constructor() {
6
+ this._components = new Map();
7
+ }
8
+ /**
9
+ * Register a React component.
10
+ *
11
+ * @param name - The unique name/identifier for the component
12
+ * @param component - The React component
13
+ */
14
+ add(name, component) {
15
+ if (this._components.has(name)) {
16
+ console.warn(`Component '${name}' is already registered and will be overwritten.`);
17
+ }
18
+ this._components.set(name, component);
19
+ }
20
+ /**
21
+ * Get a registered component by name.
22
+ *
23
+ * @param name - The name of the component
24
+ * @returns the React component, or undefined if not found
25
+ */
26
+ get(name) {
27
+ return this._components.get(name);
28
+ }
29
+ /**
30
+ * Check if a component is registered.
31
+ *
32
+ * @param name - The name of the component
33
+ * @returns whether the component is registered
34
+ */
35
+ has(name) {
36
+ return this._components.has(name);
37
+ }
38
+ /**
39
+ * Get all registered component names.
40
+ *
41
+ * @returns the component names
42
+ */
43
+ getNames() {
44
+ return Array.from(this._components.keys());
45
+ }
46
+ }
package/lib/token.d.ts CHANGED
@@ -1,5 +1,7 @@
1
1
  import { IRenderMime } from '@jupyterlab/rendermime-interfaces';
2
+ import { TranslationBundle } from '@jupyterlab/translation';
2
3
  import { Token } from '@lumino/coreutils';
4
+ import * as React from 'react';
3
5
  /**
4
6
  * The token providing the chat components renderer.
5
7
  */
@@ -8,28 +10,147 @@ export declare const IComponentsRendererFactory: Token<IComponentsRendererFactor
8
10
  * The callback to approve or reject a tool.
9
11
  */
10
12
  export type ToolCallApproval = ((targetId: string, approvalId: string, approve: boolean) => void) | null;
13
+ /**
14
+ * The callback to remove a queued message.
15
+ */
16
+ export type RemoveQueuedMessage = ((targetId: string, messageId: string) => void) | null;
11
17
  /**
12
18
  * The interface for components renderer factory.
13
19
  */
14
20
  export interface IComponentsRendererFactory extends IRenderMime.IRendererFactory {
21
+ /**
22
+ * The registry of React components available for rendering.
23
+ */
24
+ registry: IComponentRegistry;
15
25
  /**
16
26
  * The callback to approve or reject a tool.
17
27
  */
18
28
  toolCallApproval: ToolCallApproval;
29
+ /**
30
+ * The callback to remove a queued message.
31
+ */
32
+ removeQueuedMessage: RemoveQueuedMessage;
33
+ }
34
+ /**
35
+ * The interface for the component registry.
36
+ */
37
+ export interface IComponentRegistry {
38
+ /**
39
+ * Register a React component.
40
+ *
41
+ * @param name - The unique name/identifier for the component
42
+ * @param component - The React component
43
+ */
44
+ add(name: string, component: React.ComponentType<any>): void;
45
+ /**
46
+ * Get a registered component by name.
47
+ *
48
+ * @param name - The name of the component
49
+ * @returns The React component, or undefined if not found
50
+ */
51
+ get(name: string): React.ComponentType<any> | undefined;
52
+ /**
53
+ * Check if a component is registered.
54
+ *
55
+ * @param name - The name of the component
56
+ * @returns True if the component is registered
57
+ */
58
+ has(name: string): boolean;
59
+ /**
60
+ * Get all registered component names.
61
+ *
62
+ * @returns Array of component names
63
+ */
64
+ getNames(): string[];
65
+ }
66
+ /**
67
+ * The minimal required properties for the component.
68
+ */
69
+ export interface IComponentProps {
70
+ /**
71
+ * The translation bundle.
72
+ */
73
+ trans: TranslationBundle;
19
74
  }
20
75
  /**
21
- * Tool call status types.
76
+ * A file diff target.
22
77
  */
23
- export type ToolCallStatus = 'pending' | 'awaiting_approval' | 'approved' | 'rejected' | 'completed' | 'error';
78
+ export interface IInlineDiffFileTarget {
79
+ /**
80
+ * Discriminator for a regular file diff target.
81
+ */
82
+ kind: 'file';
83
+ /**
84
+ * Path of the file being diffed.
85
+ */
86
+ path: string;
87
+ }
88
+ /**
89
+ * A notebook cell diff target.
90
+ */
91
+ export interface IInlineDiffNotebookCellTarget {
92
+ /**
93
+ * Discriminator for a notebook cell source diff target.
94
+ */
95
+ kind: 'cell';
96
+ /**
97
+ * Path of the notebook containing the cell.
98
+ */
99
+ notebookPath: string;
100
+ /**
101
+ * Stable cell identifier, when available from the producer.
102
+ */
103
+ cellId?: string;
104
+ /**
105
+ * Zero-based notebook cell index used for the default display label.
106
+ */
107
+ cellIndex?: number;
108
+ }
109
+ /**
110
+ * A supported inline diff target.
111
+ */
112
+ export type IInlineDiffTarget = IInlineDiffFileTarget | IInlineDiffNotebookCellTarget;
113
+ /**
114
+ * A single inline diff entry.
115
+ */
116
+ export interface IInlineDiff {
117
+ /**
118
+ * Structured target metadata.
119
+ */
120
+ target: IInlineDiffTarget;
121
+ /**
122
+ * Optional explicit label for the diff header.
123
+ */
124
+ label?: string;
125
+ /**
126
+ * Updated text content for the diff target.
127
+ */
128
+ newText: string;
129
+ /**
130
+ * Previous text content for the diff target.
131
+ */
132
+ oldText?: string;
133
+ }
134
+ /**
135
+ * Metadata for rendering inline diffs.
136
+ */
137
+ export interface IInlineDiffMetadata {
138
+ /**
139
+ * List of inline diff entries to render.
140
+ */
141
+ diffs: IInlineDiff[];
142
+ }
143
+ /**
144
+ * A single queued message entry.
145
+ */
146
+ export interface IQueuedMessage {
147
+ id: string;
148
+ body: string;
149
+ }
24
150
  /**
25
- * Options for building tool call HTML.
151
+ * Metadata for the message queue component.
26
152
  */
27
- export interface IToolCallMetadata {
28
- toolName: string;
29
- input: string;
30
- status: ToolCallStatus;
31
- summary?: string;
32
- output?: string;
153
+ export interface IMessageQueueMetadata {
154
+ messages: IQueuedMessage[];
33
155
  targetId?: string;
34
- approvalId?: string;
35
156
  }