@pillar-ai/sdk 0.1.14 → 0.1.15

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Pillar, Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -157,6 +157,18 @@ export interface ActionDefinition<TData = Record<string, unknown>> {
157
157
  * @default false
158
158
  */
159
159
  returns?: boolean;
160
+ /**
161
+ * Concrete examples of valid parameter objects for the AI to reference.
162
+ *
163
+ * Each example should have a `description` explaining the scenario
164
+ * and a `parameters` object matching the `dataSchema`.
165
+ * Useful for complex schemas where the AI benefits from seeing
166
+ * what a correct call looks like.
167
+ */
168
+ parameterExamples?: Array<{
169
+ description: string;
170
+ parameters: Record<string, unknown>;
171
+ }>;
160
172
  /**
161
173
  * Handler function executed when the action is triggered.
162
174
  *
@@ -189,6 +201,10 @@ export interface ActionManifestEntry {
189
201
  data_schema?: ActionDataSchema;
190
202
  default_data?: Record<string, unknown>;
191
203
  required_context?: Record<string, unknown>;
204
+ parameter_examples?: Array<{
205
+ description: string;
206
+ parameters: Record<string, unknown>;
207
+ }>;
192
208
  }
193
209
  /**
194
210
  * Action manifest - synced to server during CI/CD.
@@ -216,6 +232,11 @@ export interface ActionManifest {
216
232
  * Action definitions (without handlers).
217
233
  */
218
234
  actions: ActionManifestEntry[];
235
+ /**
236
+ * Custom agent guidance synced alongside actions.
237
+ * Injected into the AI agent's prompt as product_guidance.
238
+ */
239
+ agentGuidance?: string;
219
240
  }
220
241
  /**
221
242
  * Client info set during SDK initialization.
@@ -270,6 +291,15 @@ export interface SyncActionDefinition<TData = Record<string, unknown>> {
270
291
  * If true, the handler's return value is sent back to the agent.
271
292
  */
272
293
  returns?: boolean;
294
+ /**
295
+ * Concrete examples of valid parameter objects for the AI to reference.
296
+ * Each example should have a `description` and a `parameters` object
297
+ * matching the `dataSchema`.
298
+ */
299
+ parameterExamples?: Array<{
300
+ description: string;
301
+ parameters: Record<string, unknown>;
302
+ }>;
273
303
  }
274
304
  /**
275
305
  * Map of action name to sync definition (no handlers).
@@ -91,16 +91,44 @@ export interface ConversationSummary {
91
91
  lastMessageAt: string | null;
92
92
  messageCount: number;
93
93
  }
94
+ /**
95
+ * Display step in the agent's timeline.
96
+ * This is a human-readable timeline that includes thinking, tool decisions, and tool results.
97
+ * Used for UI display of the agent's reasoning process.
98
+ */
99
+ export interface DisplayStep {
100
+ step_type: 'thinking' | 'tool_decision' | 'parallel_tool_decision' | 'tool_result' | 'token_summary' | 'step_start' | 'generating' | 'narration';
101
+ iteration?: number;
102
+ timestamp_ms?: number;
103
+ content?: string;
104
+ tool?: string;
105
+ tools?: Array<{
106
+ tool: string;
107
+ arguments: Record<string, unknown>;
108
+ }>;
109
+ arguments?: Record<string, unknown>;
110
+ success?: boolean;
111
+ reasoning?: string;
112
+ label?: string;
113
+ [key: string]: unknown;
114
+ }
115
+ /**
116
+ * Message in conversation history.
117
+ * Contains display-oriented fields for UI rendering.
118
+ * LLM-native fields (llm_message) are kept server-side for conversation replay.
119
+ */
120
+ export interface HistoryMessage {
121
+ id: string;
122
+ role: 'user' | 'assistant';
123
+ content: string;
124
+ timestamp: string | null;
125
+ display_trace?: DisplayStep[];
126
+ }
94
127
  /**
95
128
  * Full conversation with messages.
96
129
  */
97
130
  export interface ConversationDetail extends ConversationSummary {
98
- messages: Array<{
99
- id: string;
100
- role: 'user' | 'assistant';
101
- content: string;
102
- timestamp: string | null;
103
- }>;
131
+ messages: HistoryMessage[];
104
132
  }
105
133
  export declare class APIClient {
106
134
  private config;
@@ -158,7 +186,7 @@ export declare class APIClient {
158
186
  * @returns Promise with signed URL and expiration
159
187
  */
160
188
  uploadImage(file: File): Promise<ImageUploadResponse>;
161
- chat(message: string, history?: ChatMessage[], onChunk?: (chunk: string) => void, articleSlug?: string, existingConversationId?: string | null, onActions?: (actions: TaskButtonData[]) => void, userContext?: UserContextItem[], images?: ChatImage[], onProgress?: (progress: ProgressEvent) => void, onConversationStarted?: (conversationId: string, messageId?: string) => void, onActionRequest?: (request: ActionRequest) => Promise<void>): Promise<ChatResponse>;
189
+ chat(message: string, history?: ChatMessage[], onChunk?: (chunk: string) => void, articleSlug?: string, existingConversationId?: string | null, onActions?: (actions: TaskButtonData[]) => void, userContext?: UserContextItem[], images?: ChatImage[], onProgress?: (progress: ProgressEvent) => void, onConversationStarted?: (conversationId: string, assistantMessageId?: string) => void, onActionRequest?: (request: ActionRequest) => Promise<void>, signal?: AbortSignal, onRequestId?: (requestId: number) => void): Promise<ChatResponse>;
162
190
  /**
163
191
  * Legacy chat method using the old /ai/chat/ endpoint.
164
192
  * @deprecated Use chat() which uses the MCP protocol.
@@ -57,6 +57,27 @@ export interface ActionRequest {
57
57
  /** Unique ID for this specific tool invocation (for result correlation) */
58
58
  tool_call_id?: string;
59
59
  }
60
+ /** Token usage data from the agentic loop (sent after each LLM iteration) */
61
+ export interface TokenUsage {
62
+ /** Input tokens for this iteration */
63
+ prompt_tokens: number;
64
+ /** Output tokens for this iteration */
65
+ completion_tokens: number;
66
+ /** Cumulative prompt tokens across all iterations */
67
+ total_prompt_tokens: number;
68
+ /** Cumulative completion tokens across all iterations */
69
+ total_completion_tokens: number;
70
+ /** Current total tokens in context */
71
+ total_used: number;
72
+ /** Maximum context window for the model */
73
+ context_window: number;
74
+ /** Current context occupancy percentage (0-100) */
75
+ occupancy_pct: number;
76
+ /** Name of the model in use */
77
+ model_name: string;
78
+ /** Current iteration number (0-indexed) */
79
+ iteration: number;
80
+ }
60
81
  /** Streaming callbacks for tool calls */
61
82
  export interface StreamCallbacks {
62
83
  /** Called for each text token */
@@ -69,8 +90,8 @@ export interface StreamCallbacks {
69
90
  onRegisteredActions?: (actions: Record<string, unknown>[]) => void;
70
91
  /** Called on error */
71
92
  onError?: (error: string) => void;
72
- /** Called when conversation_started event is received (early conversation_id) */
73
- onConversationStarted?: (conversationId: string, messageId?: string) => void;
93
+ /** Called when conversation_started event is received (confirms conversation tracking) */
94
+ onConversationStarted?: (conversationId: string, assistantMessageId?: string) => void;
74
95
  /** Called when stream is complete */
75
96
  onComplete?: (conversationId?: string, queryLogId?: string) => void;
76
97
  /** Called for progress updates (search, query, generating, thinking, etc.) */
@@ -89,8 +110,12 @@ export interface StreamCallbacks {
89
110
  progress_id?: string;
90
111
  message?: string;
91
112
  }) => void;
113
+ /** Called immediately with the request ID (for cancellation support) */
114
+ onRequestId?: (requestId: number) => void;
92
115
  /** Called when agent requests action execution (unified handler) */
93
116
  onActionRequest?: (request: ActionRequest) => Promise<void>;
117
+ /** Called when token usage is updated (after each LLM iteration) */
118
+ onTokenUsage?: (usage: TokenUsage) => void;
94
119
  }
95
120
  /** Image for chat requests (from upload-image endpoint) */
96
121
  export interface ChatImage {
@@ -174,7 +199,18 @@ export declare class MCPClient {
174
199
  /** Registered actions from previous turns (for dynamic action tools) */
175
200
  registeredActions?: Record<string, unknown>[];
176
201
  signal?: AbortSignal;
202
+ /** Conversation ID - generated client-side, always provided */
203
+ conversationId?: string;
177
204
  }): Promise<ToolResult>;
205
+ /**
206
+ * Cancel an active streaming request.
207
+ *
208
+ * Sends a notifications/cancel JSON-RPC request to the backend, which
209
+ * signals the StreamRegistry to stop the LLM stream and cease billing.
210
+ *
211
+ * @param requestId - The JSON-RPC request ID of the stream to cancel
212
+ */
213
+ cancelStream(requestId: number | string): Promise<void>;
178
214
  /**
179
215
  * Send action result back to the agent.
180
216
  *
@@ -221,10 +257,10 @@ export declare class MCPClient {
221
257
  * from where it was interrupted.
222
258
  *
223
259
  * @param conversationId - The conversation to resume
224
- * @param userContext - Optional current page context
260
+ * @param userContext - Optional current page context (highlighted text, DOM snapshot, etc.)
225
261
  * @param callbacks - Streaming callbacks
226
262
  */
227
- resumeConversation(conversationId: string, userContext: Record<string, unknown> | undefined, callbacks: StreamCallbacks): Promise<void>;
263
+ resumeConversation(conversationId: string, userContext: UserContextItem[] | undefined, callbacks: StreamCallbacks): Promise<void>;
228
264
  /**
229
265
  * Handle events from the resume stream.
230
266
  */
package/dist/cli/sync.js CHANGED
@@ -181,6 +181,8 @@ function buildManifest(actions, platform, version, gitSha, agentGuidance) {
181
181
  entry.default_data = definition.defaultData;
182
182
  if (definition.requiredContext)
183
183
  entry.required_context = definition.requiredContext;
184
+ if (definition.parameterExamples?.length)
185
+ entry.parameter_examples = definition.parameterExamples;
184
186
  entries.push(entry);
185
187
  }
186
188
  const manifest = {
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Page Pilot Banner Component
3
+ * Shows "Page being piloted by Agent" with stop button during interact_with_page actions.
4
+ * When a destructive action is detected, shows a confirmation variant with Allow/Deny buttons.
5
+ */
6
+ import { h } from 'preact';
7
+ export declare function PagePilotBanner(): h.JSX.Element | null;
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Page Pilot Manager
3
+ * Manages the "Page being piloted by Agent" banner, rendering it outside Shadow DOM
4
+ * so it appears above all other content on the page.
5
+ */
6
+ export declare class PagePilotManager {
7
+ private container;
8
+ private stylesInjected;
9
+ private unsubscribe;
10
+ private themeObserver;
11
+ private primaryColor;
12
+ /**
13
+ * Detect the current theme from the document
14
+ * Checks for .dark class (next-themes) or data-theme attribute
15
+ */
16
+ private detectThemeFromDOM;
17
+ /**
18
+ * Apply theme mode to container element
19
+ */
20
+ private applyTheme;
21
+ /**
22
+ * Set up observer to watch for theme changes on documentElement
23
+ */
24
+ private setupThemeObserver;
25
+ /**
26
+ * Initialize the page pilot manager
27
+ * @param primaryColor - Optional primary color from theme config to override the default
28
+ */
29
+ init(primaryColor?: string): void;
30
+ /**
31
+ * Update the primary color used by the banner
32
+ */
33
+ setPrimaryColor(color: string): void;
34
+ /**
35
+ * Destroy the page pilot manager
36
+ */
37
+ destroy(): void;
38
+ /**
39
+ * Render the banner component
40
+ */
41
+ private render;
42
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Page Pilot Components
3
+ * Banner and manager for displaying "Page being piloted by Agent" indicator
4
+ */
5
+ export { PagePilotBanner } from './PagePilotBanner';
6
+ export { PagePilotManager } from './PagePilotManager';
7
+ export { PAGE_PILOT_STYLES } from './styles';
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Page Pilot Banner CSS Styles
3
+ * Injected into the document head (outside Shadow DOM)
4
+ * Uses the same CSS variables as the Pillar panel for consistent theming
5
+ */
6
+ export declare const PAGE_PILOT_STYLES = "\n/* Pillar Page Pilot Banner Styles */\n\n/* Define CSS variables at the container level (same as panel) */\n#pillar-page-pilot-container {\n /* Core colors - Light mode (default) */\n --pillar-primary: #2563eb;\n --pillar-primary-hover: #1d4ed8;\n --pillar-bg: #ffffff;\n --pillar-bg-secondary: #f9fafb;\n --pillar-text: #1a1a1a;\n --pillar-text-secondary: #374151;\n --pillar-border: #e5e7eb;\n --pillar-shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1);\n --pillar-font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;\n --pillar-radius-lg: 8px;\n --pillar-radius-md: 6px;\n --pillar-transition-fast: 0.15s ease;\n}\n\n/* Dark mode - Auto-detect from system preference */\n@media (prefers-color-scheme: dark) {\n #pillar-page-pilot-container:not([data-theme=\"light\"]) {\n --pillar-primary: #3b82f6;\n --pillar-primary-hover: #60a5fa;\n --pillar-bg: #1a1a1a;\n --pillar-bg-secondary: #262626;\n --pillar-text: #f5f5f5;\n --pillar-text-secondary: #e5e5e5;\n --pillar-border: #404040;\n --pillar-shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.4);\n }\n}\n\n/* Dark mode - Manual override via html class or data attribute */\nhtml.dark #pillar-page-pilot-container,\n[data-theme=\"dark\"] #pillar-page-pilot-container,\n#pillar-page-pilot-container[data-theme=\"dark\"] {\n --pillar-primary: #3b82f6;\n --pillar-primary-hover: #60a5fa;\n --pillar-bg: #1a1a1a;\n --pillar-bg-secondary: #262626;\n --pillar-text: #f5f5f5;\n --pillar-text-secondary: #e5e5e5;\n --pillar-border: #404040;\n --pillar-shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.4);\n}\n\n@keyframes pillar-pulse {\n 0%, 100% {\n opacity: 1;\n transform: scale(1);\n }\n 50% {\n opacity: 0.6;\n transform: scale(1.1);\n }\n}\n\n@keyframes pillar-banner-fade-in {\n from {\n opacity: 0;\n transform: translateY(-100%);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n._pillar-page-pilot-banner {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n z-index: 99999;\n font-family: var(--pillar-font-family);\n display: flex;\n justify-content: center;\n pointer-events: none;\n animation: pillar-banner-fade-in 0.2s ease-out;\n}\n\n/* Viewport outline \u2014 3px border on left, right, bottom; top handled by tab shape */\n._pillar-page-pilot-banner::before {\n content: '';\n position: fixed;\n inset: 0;\n border: 3px solid var(--pillar-primary);\n border-top: none;\n pointer-events: none;\n z-index: 99998;\n}\n\n/* Top border segments on either side of the tab */\n._pillar-page-pilot-banner::after {\n content: '';\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n height: 3px;\n background: var(--pillar-primary);\n pointer-events: none;\n z-index: 99997;\n}\n\n._pillar-page-pilot-banner__content {\n position: relative;\n z-index: 99999;\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 6px 20px;\n background: var(--pillar-primary);\n color: #ffffff;\n border-bottom-left-radius: var(--pillar-radius-lg);\n border-bottom-right-radius: var(--pillar-radius-lg);\n pointer-events: auto;\n}\n\n._pillar-page-pilot-banner__indicator {\n width: 8px;\n height: 8px;\n background: #ffffff;\n border-radius: 50%;\n animation: pillar-pulse 1.5s ease-in-out infinite;\n flex-shrink: 0;\n}\n\n._pillar-page-pilot-banner__text {\n font-size: 13px;\n font-weight: 500;\n color: #ffffff;\n white-space: nowrap;\n}\n\n._pillar-page-pilot-banner__stop {\n display: flex;\n align-items: center;\n gap: 4px;\n padding: 5px 10px;\n margin-left: 4px;\n font-family: inherit;\n font-size: 12px;\n font-weight: 500;\n color: #ffffff;\n background: rgba(255, 255, 255, 0.15);\n border: 1px solid rgba(255, 255, 255, 0.3);\n border-radius: var(--pillar-radius-md);\n cursor: pointer;\n transition: all var(--pillar-transition-fast);\n}\n\n._pillar-page-pilot-banner__stop:hover {\n background: rgba(255, 255, 255, 0.25);\n border-color: rgba(255, 255, 255, 0.5);\n}\n\n._pillar-page-pilot-banner__stop:active {\n transform: scale(0.97);\n}\n\n._pillar-page-pilot-banner__stop-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 14px;\n height: 14px;\n}\n\n._pillar-page-pilot-banner__stop-icon svg {\n width: 100%;\n height: 100%;\n}\n\n/* Confirmation variant \u2014 amber/warning theme */\n._pillar-page-pilot-banner--confirm ._pillar-page-pilot-banner__content {\n background: #d97706;\n}\n\n._pillar-page-pilot-banner--confirm::before {\n border-color: #d97706;\n}\n\n._pillar-page-pilot-banner--confirm::after {\n background: #d97706;\n}\n\n._pillar-page-pilot-banner__warning-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 14px;\n height: 14px;\n flex-shrink: 0;\n}\n\n._pillar-page-pilot-banner__warning-icon svg {\n width: 100%;\n height: 100%;\n}\n\n._pillar-page-pilot-banner__deny {\n display: flex;\n align-items: center;\n padding: 5px 12px;\n margin-left: 4px;\n font-family: inherit;\n font-size: 12px;\n font-weight: 500;\n color: #ffffff;\n background: rgba(255, 255, 255, 0.15);\n border: 1px solid rgba(255, 255, 255, 0.3);\n border-radius: var(--pillar-radius-md);\n cursor: pointer;\n transition: all var(--pillar-transition-fast);\n}\n\n._pillar-page-pilot-banner__deny:hover {\n background: rgba(255, 255, 255, 0.25);\n border-color: rgba(255, 255, 255, 0.5);\n}\n\n._pillar-page-pilot-banner__deny:active {\n transform: scale(0.97);\n}\n\n._pillar-page-pilot-banner__allow {\n display: flex;\n align-items: center;\n padding: 5px 12px;\n font-family: inherit;\n font-size: 12px;\n font-weight: 600;\n color: #d97706;\n background: #ffffff;\n border: 1px solid rgba(255, 255, 255, 0.8);\n border-radius: var(--pillar-radius-md);\n cursor: pointer;\n transition: all var(--pillar-transition-fast);\n}\n\n._pillar-page-pilot-banner__allow:hover {\n background: #fef3c7;\n}\n\n._pillar-page-pilot-banner__allow:active {\n transform: scale(0.97);\n}\n";
@@ -2,13 +2,11 @@
2
2
  * Panel Header Component
3
3
  * Navigation header with back, home, history, and close buttons
4
4
  */
5
- import { h } from 'preact';
6
- import { type ViewType } from '../../store/router';
5
+ import { type ViewType } from "../../store/router";
7
6
  interface HeaderProps {
8
7
  currentView: ViewType;
9
- customTitle?: string;
10
8
  /** Hide back and home navigation buttons */
11
9
  hideNavigation?: boolean;
12
10
  }
13
- export declare function Header({ currentView, customTitle, hideNavigation }: HeaderProps): h.JSX.Element;
11
+ export declare function Header({ currentView, hideNavigation }: HeaderProps): import("preact").JSX.Element;
14
12
  export {};
@@ -2,5 +2,4 @@
2
2
  * Panel Content Component
3
3
  * Main panel layout with header, content, and chat input
4
4
  */
5
- import { h } from 'preact';
6
- export declare function PanelContent(): h.JSX.Element;
5
+ export declare function PanelContent(): import("preact").JSX.Element;
@@ -18,6 +18,10 @@ interface UnifiedChatInputProps {
18
18
  showImageUpload?: boolean;
19
19
  /** Additional CSS class for the wrapper */
20
20
  className?: string;
21
+ /** Whether a response is currently streaming (shows Stop button) */
22
+ isStreaming?: boolean;
23
+ /** Called when user clicks the Stop button to cancel streaming */
24
+ onStop?: () => void;
21
25
  }
22
- export declare function UnifiedChatInput({ placeholder, disabled, onSubmit, showContextTags, showImageUpload, className, }: UnifiedChatInputProps): import("preact").JSX.Element;
26
+ export declare function UnifiedChatInput({ placeholder, disabled, onSubmit, showContextTags, showImageUpload, className, isStreaming, onStop, }: UnifiedChatInputProps): import("preact").JSX.Element;
23
27
  export {};