@directivsys/vue-sdk
v0.1.8
Published
Vue bindings for DirectivSys built on top of @directivsys/core-sdk.
Readme
@directivsys/vue-sdk
@directivsys/vue-sdk is the Vue 3 adapter for DirectivSys. It provides pre-built components, composables, and a theming system for building AI-powered chat and analytics interfaces. It builds on top of @directivsys/core-sdk and exposes Vue-native plugin installation, dependency injection, and composable APIs while reusing the shared transport and orchestration runtime from the core package.
Features
✨ Chat Interface — DirectivSysChatbox component with message history, voice input/output, and file uploads
🔍 Search — DirectivSysSearch component with intelligent dropdown results
📊 Analytics — AnalyticsWidget and AnalyticsDashboard for monitoring directives and metrics
📈 Reports — ReportsDashboard with tabbed views for executive, supply chain, portfolio, and data quality insights
💾 Chat Persistence — Automatic message history persistence with "load more" functionality
🎨 Themes — Built-in light/dark themes with customization support
🧩 Composables — Analytics hooks for configs, results, date ranges, and data fetching
⚡ Framework-agnostic utilities — Request caching, analytics API client, and date range utilities
Relationship to the core package
| Concern | Package |
| --- | --- |
| Transport clients, conversation controller, shared contracts, and browser voice adapters | @directivsys/core-sdk |
| Vue components, composables, themes, and context injection | @directivsys/vue-sdk |
The Vue package keeps the framework-specific concerns centered on provide and inject, reactive refs, and composable ergonomics, while the orchestration lifecycle remains in the shared core runtime.
Installation
npm install @directivsys/vue-sdk @directivsys/core-sdk vueor just
npm install @directivsys/vue-sdkPlugin setup
import { createApp } from "vue";
import { createDirectivSysPlugin } from "@directivsys/vue-sdk";
import App from "./App.vue";
const app = createApp(App);
app.use(
createDirectivSysPlugin({
apiKey: "your-api-key",
config: {
timeout: 30000,
},
theme: {
mode: "light", // "light" | "dark"
},
}),
);
app.mount("#app");Components
DirectivSysChatbox
Full-featured chat interface with message history, voice I/O, and file uploads.
<script setup lang="ts">
import { ref } from "vue";
import { DirectivSysChatbox } from "@directivsys/vue-sdk";
const currentContext = ref({
userId: "user-123",
interfaceState: {
currentPageName: "Dashboard",
},
});
</script>
<template>
<DirectivSysChatbox
:current-context="currentContext"
:on-intent-detected="handleIntent"
placeholder="Ask me anything..."
height="600px"
/>
</template>Props:
onIntentDetected(required) — Callback when the agent detects an intentcurrentContext(required) — Current user context (can be reactive ref)placeholder— Input placeholder textheight— Component height (default: "500px")theme— Partial theme overrideonError,onSpeechStart,onSpeechEnd,onTranscript,onAgentResponse— Event callbacks
Features:
- Auto-scrolling to newest messages
- "Load earlier messages" button with scroll position restoration
- Typing indicator animation
- Voice input/output with start/stop controls
- Auto-expanding textarea with Shift+Enter for newlines
- File upload support for images and documents
- Message expansion for long text
DirectivSysSearch
Intelligent search interface with dropdown results.
<script setup lang="ts">
import { ref } from "vue";
import { DirectivSysSearch } from "@directivsys/vue-sdk";
const currentContext = ref({
userId: "user-123",
interfaceState: { currentPageName: "Search" },
});
</script>
<template>
<DirectivSysSearch
:current-context="currentContext"
:on-intent-detected="handleIntent"
width="100%"
max-results="5"
/>
</template>Props:
onIntentDetected(required) — Intent detection callbackcurrentContext(required) — User contextplaceholder— Search placeholderwidth— Component widthmaxResults— Max results to display (default: 5)theme— Theme override- Event callbacks same as Chatbox
AnalyticsWidget
Floating button that displays enabled analytics count.
<template>
<AnalyticsWidget
position="bottom-right"
@directive-action="handleDirectiveAction"
/>
</template>Props:
position— Widget position ("bottom-right" | "bottom-left")theme— Theme overrideonDirectiveAction— Handle directive execute/decline
AnalyticsDashboard
Sidebar + content layout for viewing analytics configs and directives.
<template>
<AnalyticsDashboard
auto-refresh-interval="60000"
@directive-action="handleDirectiveAction"
/>
</template>ReportsDashboard
Tabbed dashboard with 5 report types:
- Executive Dashboard (metrics, trends)
- Supply Chain Risk (risk matrix, health gauges)
- Execution Audit Trail (audit log, statuses)
- Portfolio Health (health scores)
- Data Quality Automation (quality metrics)
<template>
<ReportsDashboard />
</template>Utility Components
MetricCard.vue— KPI display with trendStatusBadge.vue— Status indicator pillProgressBar.vue— Progress visualizationReportLayout.vue— Shared report wrapper
Composables
useDirectivSys
Main composable for chat functionality.
const {
messages, // ComputedRef<ChatMessage[]>
isLoading, // ComputedRef<boolean>
error, // ComputedRef<Error | null>
isListening, // ComputedRef<boolean>
hasMoreMessages, // ComputedRef<boolean> — true if older messages available
isLoadingHistory, // ComputedRef<boolean> — true while loading history
sendChatQuery, // (query: string) => Promise<void>
clearMessages, // () => void
loadMoreMessages, // () => Promise<void>
startVoiceInput, // () => void
stopVoiceInput, // () => void
stopSpeechPlayback, // () => void
} = useDirectivSys({
currentContext,
onIntentDetected,
storageAdapter, // Optional: custom storage (defaults to localStorage)
// ... other callbacks
});Chat Persistence:
The controller automatically persists the last 50 messages to localStorage (key: directivsys_chat_{userId}). On mount, it restores the session and displays the last 20 messages. Older messages are loaded on-demand via loadMoreMessages().
Scroll Position Anchoring:
When loading older messages, capture scroll height before calling loadMoreMessages(), then restore the scroll offset after render:
const scrollAnchorRef = ref(0);
const handleLoadMore = async () => {
const el = messagesContainerRef.value;
if (el) {
scrollAnchorRef.value = el.scrollHeight; // Capture height
}
await loadMoreMessages();
// After DOM updates, restore scroll position:
if (el) {
el.scrollTop = el.scrollHeight - scrollAnchorRef.value;
}
};useAnalyticsConfigs
Fetch all analytics configurations.
const { configs, isLoading, error, refetch } = useAnalyticsConfigs();useAnalyticsResult
Fetch result for a specific analytics type.
const { result, isLoading, error, refetch } = useAnalyticsResult(analyticsType);useDateRange
Manage date range selection.
const { selectedOption, setSelectedOption, startDate, endDate, label } = useDateRange("past-month");
// Options: "past-week", "past-month", "past-3-months", "past-6-months", "past-year"useDirectiveAction
Handle directive execute/decline actions.
const { handleAction, isProcessing, error } = useDirectiveAction(onDirectiveAction);
await handleAction(directive, "execute" | "decline");useReportData
Generic data fetching with request caching (TTL: 5 minutes).
const { data, loading, error, refetch } = useReportData(
() => fetchSomeData(),
[dependency1, dependency2],
{ enabled: true, ttl: 5 * 60 * 1000 }
);Themes
Built-in Themes
import { lightTheme, darkTheme } from "@directivsys/vue-sdk";Custom Theme
import { createCustomTheme, lightTheme } from "@directivsys/vue-sdk";
const customTheme = createCustomTheme(lightTheme, {
colors: {
primary: "#5e35b1",
secondary: "#ff6f00",
// ... override other colors
},
});Theme Structure
interface Theme {
name: string;
colors: {
primary: string;
secondary: string;
background: string;
surface: string;
text: string;
textSecondary: string;
border: string;
error: string;
success: string;
};
spacing: {
xs: string; // 4px
sm: string; // 8px
md: string; // 16px
lg: string; // 24px
xl: string; // 32px
};
fontSizes: {
xs: string; // 12px
sm: string; // 14px
md: string; // 16px
lg: string; // 18px
xl: string; // 24px
};
borderRadius: string; // 8px
boxShadow: string;
}Composable Usage Example
import { ref } from "vue";
import { useDirectivSys, useAnalyticsConfigs } from "@directivsys/vue-sdk";
const currentContext = ref({
userId: "user-123",
interfaceState: {
currentPageName: "Inventory Dashboard",
},
});
const sdk = useDirectivSys({
currentContext,
onIntentDetected: async (toolCall) => ({
status: "success",
summary: `Handled ${toolCall.toolName}`,
}),
});
await sdk.sendChatQuery("Summarize the latest supply chain risk.");
// Analytics
const { configs, isLoading } = useAnalyticsConfigs();Utilities
AnalyticsAPI
HTTP client for analytics endpoints.
import { AnalyticsAPI } from "@directivsys/vue-sdk";
const api = new AnalyticsAPI(config);
const configs = await api.getConfigs();
const result = await api.getLatestResult("analyticsType");
await api.updateDirectiveStatus(directiveId, "executed");requestCache
Singleton cache for deduplicating requests (5-minute TTL).
import { requestCache } from "@directivsys/vue-sdk";
const result = await requestCache.get(fetchFn, cacheKey, ttl);
requestCache.invalidate(fetchFn, cacheKey);DateRangeService
Date range utilities.
import { DateRangeService } from "@directivsys/vue-sdk";
const range = DateRangeService.getDateRange("past-month");
// { startDate, endDate, label }Exported Types
All types from @directivsys/core-sdk are re-exported, plus:
export type Theme;
export type ThemeMode; // "light" | "dark" | "custom"
export type ThemeColors;
export type AnalyticsConfig;
export type AnalyticsResult;
export type AnalyticsDirective;
export type AnalyticsMetric;
export type AnalyticsObservation;
export type DirectiveActionCallback;
// ... and moreBest Practices
Message History Loading
Implement scroll anchoring to keep the user at the same message when loading history:
<script setup>
const messagesContainerRef = ref();
const scrollAnchorRef = ref(0);
const handleLoadMore = async () => {
const el = messagesContainerRef.value;
if (el) {
scrollAnchorRef.value = el.scrollHeight;
}
await sdk.loadMoreMessages();
// Restore scroll position in next tick
nextTick(() => {
if (el) {
el.scrollTop = el.scrollHeight - scrollAnchorRef.value;
}
});
};
</script>Custom Storage Adapter
Use a custom storage backend instead of localStorage:
const customStorage = {
getItem: (key) => sessionStorage.getItem(key),
setItem: (key, value) => sessionStorage.setItem(key, value),
removeItem: (key) => sessionStorage.removeItem(key),
};
const sdk = useDirectivSys({
currentContext,
onIntentDetected,
storageAdapter: customStorage,
});Error Handling
const { error, isLoading } = useDirectivSys({
currentContext,
onIntentDetected,
onError: (error) => {
console.error("DirectivSys error:", error);
// Show user-facing error message
},
});Relationship to React SDK
This Vue SDK is feature-parity with @directivsys/react-sdk. Most concepts map directly:
- React hooks → Vue composables
- React components → Vue SFCs
- Context API → provide/inject
- useState → ref/reactive
- useEffect → watch
The theme system, analytics utilities, and type definitions are fully shared across both SDKs.
License
MIT
