Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -441,3 +441,32 @@ jobs:
run: |
echo "=== API Server Logs ==="
cat /tmp/api-server.log || echo "No API server log found"

test-litellm-integration:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Install uv
uses: astral-sh/setup-uv@v5
with:
enable-cache: true
prune-cache: false

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version-file: ".python-version"

- name: Build litellm integration
working-directory: ./hindsight-integrations/litellm
run: uv build

- name: Install dependencies
working-directory: ./hindsight-integrations/litellm
run: uv sync --extra dev

- name: Run tests
working-directory: ./hindsight-integrations/litellm
run: uv run pytest tests -v
6 changes: 5 additions & 1 deletion hindsight-api/hindsight_api/engine/llm_wrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,9 +175,13 @@ async def call(
is_reasoning_model = any(x in model_lower for x in ["gpt-5", "o1", "o3"])

# For GPT-4 and GPT-4.1 models, cap max_completion_tokens to 32000
# For GPT-4o models, cap to 16384
is_gpt4_model = any(x in model_lower for x in ["gpt-4.1", "gpt-4-"])
is_gpt4o_model = "gpt-4o" in model_lower
if max_completion_tokens is not None:
if is_gpt4_model and max_completion_tokens > 32000:
if is_gpt4o_model and max_completion_tokens > 16384:
max_completion_tokens = 16384
elif is_gpt4_model and max_completion_tokens > 32000:
max_completion_tokens = 32000
# For reasoning models, max_completion_tokens includes reasoning + output tokens
# Enforce minimum of 16000 to ensure enough space for both
Expand Down
10 changes: 6 additions & 4 deletions hindsight-api/hindsight_api/pg0.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,9 @@ async def start(self, max_retries: int = 3, retry_delay: float = 2.0) -> str:
loop = asyncio.get_event_loop()
info = await loop.run_in_executor(None, pg0.start)
logger.info(f"PostgreSQL started on port {self.port}")
return info.uri
# Construct URI manually since pg0-embedded may return None
uri = info.uri if info and info.uri else f"postgresql://{self.username}:{self.password}@localhost:{self.port}/{self.database}"
return uri
except Exception as e:
last_error = str(e)
if attempt < max_retries:
Expand Down Expand Up @@ -89,9 +91,9 @@ async def get_uri(self) -> str:
pg0 = self._get_pg0()
loop = asyncio.get_event_loop()
info = await loop.run_in_executor(None, pg0.info)
if info is None or not info.running:
raise RuntimeError("PostgreSQL server is not running or URI not available")
return info.uri
# Construct URI manually since pg0-embedded may return None
uri = info.uri if info and info.uri else f"postgresql://{self.username}:{self.password}@localhost:{self.port}/{self.database}"
return uri

async def is_running(self) -> bool:
"""Check if the PostgreSQL server is currently running."""
Expand Down
9 changes: 9 additions & 0 deletions hindsight-control-plane/src/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -180,4 +180,13 @@ code, pre {
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}

/* Fix datetime-local calendar icon visibility in both light and dark modes */
input[type="datetime-local"]::-webkit-calendar-picker-indicator {
filter: invert(0.5);
}

.dark input[type="datetime-local"]::-webkit-calendar-picker-indicator {
filter: invert(1);
}
4 changes: 2 additions & 2 deletions hindsight-control-plane/src/components/bank-profile-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ export function BankProfileView() {
<div className="flex gap-2">
{editMode ? (
<>
<Button onClick={handleCancel} variant="outline" disabled={saving}>
<Button onClick={handleCancel} variant="secondary" disabled={saving}>
Cancel
</Button>
<Button onClick={handleSave} disabled={saving}>
Expand All @@ -258,7 +258,7 @@ export function BankProfileView() {
</>
) : (
<>
<Button onClick={loadData} variant="outline" size="sm">
<Button onClick={loadData} variant="secondary" size="sm">
<RefreshCw className="w-4 h-4 mr-2" />
Refresh
</Button>
Expand Down
15 changes: 8 additions & 7 deletions hindsight-control-plane/src/components/bank-selector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ function BankSelectorInner() {
</div>
<DialogFooter>
<Button
variant="outline"
variant="secondary"
onClick={() => {
setCreateDialogOpen(false);
setNewBankId('');
Expand Down Expand Up @@ -295,7 +295,7 @@ function BankSelectorInner() {
</DialogHeader>
<div className="py-4 space-y-4">
<div>
<label className="font-bold block mb-1 text-sm">Content *</label>
<label className="font-bold block mb-1 text-sm text-foreground">Content *</label>
<Textarea
value={docContent}
onChange={(e) => setDocContent(e.target.value)}
Expand All @@ -306,7 +306,7 @@ function BankSelectorInner() {
</div>

<div>
<label className="font-bold block mb-1 text-sm">Context</label>
<label className="font-bold block mb-1 text-sm text-foreground">Context</label>
<Input
type="text"
value={docContext}
Expand All @@ -317,16 +317,17 @@ function BankSelectorInner() {

<div className="grid grid-cols-2 gap-4">
<div>
<label className="font-bold block mb-1 text-sm">Event Date</label>
<label className="font-bold block mb-1 text-sm text-foreground">Event Date</label>
<Input
type="datetime-local"
value={docEventDate}
onChange={(e) => setDocEventDate(e.target.value)}
className="text-foreground"
/>
</div>

<div>
<label className="font-bold block mb-1 text-sm">Document ID</label>
<label className="font-bold block mb-1 text-sm text-foreground">Document ID</label>
<Input
type="text"
value={docDocumentId}
Expand All @@ -342,7 +343,7 @@ function BankSelectorInner() {
checked={docAsync}
onCheckedChange={(checked) => setDocAsync(checked as boolean)}
/>
<label htmlFor="async-doc" className="text-sm cursor-pointer">
<label htmlFor="async-doc" className="text-sm cursor-pointer text-foreground">
Process in background (async)
</label>
</div>
Expand All @@ -353,7 +354,7 @@ function BankSelectorInner() {
</div>
<DialogFooter>
<Button
variant="outline"
variant="secondary"
onClick={() => {
setDocDialogOpen(false);
setDocContent('');
Expand Down
24 changes: 12 additions & 12 deletions hindsight-control-plane/src/components/data-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -480,7 +480,7 @@ export function DataView({ factType }: DataViewProps) {
}`}
>
<TableCell className="py-2">
<div className="line-clamp-2 text-sm leading-snug">{row.text}</div>
<div className="line-clamp-2 text-sm leading-snug text-foreground">{row.text}</div>
{row.context && (
<div className="text-xs text-muted-foreground mt-0.5 truncate">{row.context}</div>
)}
Expand All @@ -506,10 +506,10 @@ export function DataView({ factType }: DataViewProps) {
<span className="text-xs text-muted-foreground">-</span>
)}
</TableCell>
<TableCell className="text-xs py-2">
<TableCell className="text-xs py-2 text-foreground">
{occurredDisplay || <span className="text-muted-foreground">-</span>}
</TableCell>
<TableCell className="text-xs py-2">
<TableCell className="text-xs py-2 text-foreground">
{mentionedDisplay || <span className="text-muted-foreground">-</span>}
</TableCell>
<TableCell className="py-2">
Expand All @@ -519,7 +519,7 @@ export function DataView({ factType }: DataViewProps) {
copyToClipboard(row.id);
}}
size="sm"
variant="ghost"
variant="secondary"
className="h-6 w-6 p-0"
title="Copy ID"
>
Expand Down Expand Up @@ -799,7 +799,7 @@ function TimelineView({ data, filteredRows }: { data: any; filteredRows: any[] }
{/* Zoom controls */}
<div className="flex items-center border border-border rounded mr-2">
<Button
variant="ghost"
variant="secondary"
size="sm"
onClick={zoomOut}
disabled={granularity === 'year'}
Expand All @@ -808,11 +808,11 @@ function TimelineView({ data, filteredRows }: { data: any; filteredRows: any[] }
>
<ZoomOut className="h-3 w-3" />
</Button>
<span className="text-[10px] px-2 min-w-[50px] text-center border-x border-border">
<span className="text-[10px] px-2 min-w-[50px] text-center border-x border-border text-foreground">
{granularityLabels[granularity]}
</span>
<Button
variant="ghost"
variant="secondary"
size="sm"
onClick={zoomIn}
disabled={granularity === 'day'}
Expand All @@ -826,7 +826,7 @@ function TimelineView({ data, filteredRows }: { data: any; filteredRows: any[] }
{/* Navigation controls */}
<div className="flex items-center border border-border rounded">
<Button
variant="ghost"
variant="secondary"
size="sm"
onClick={() => scrollToGroup(0)}
disabled={timelineGroups.length <= 1}
Expand All @@ -836,7 +836,7 @@ function TimelineView({ data, filteredRows }: { data: any; filteredRows: any[] }
<ChevronsLeft className="h-3 w-3" />
</Button>
<Button
variant="ghost"
variant="secondary"
size="sm"
onClick={() => scrollToGroup(currentIndex - 1)}
disabled={currentIndex === 0}
Expand All @@ -845,11 +845,11 @@ function TimelineView({ data, filteredRows }: { data: any; filteredRows: any[] }
>
<ChevronLeft className="h-3 w-3" />
</Button>
<span className="text-[10px] px-2 min-w-[60px] text-center border-x border-border">
<span className="text-[10px] px-2 min-w-[60px] text-center border-x border-border text-foreground">
{currentIndex + 1} / {timelineGroups.length}
</span>
<Button
variant="ghost"
variant="secondary"
size="sm"
onClick={() => scrollToGroup(currentIndex + 1)}
disabled={currentIndex >= timelineGroups.length - 1}
Expand All @@ -859,7 +859,7 @@ function TimelineView({ data, filteredRows }: { data: any; filteredRows: any[] }
<ChevronRight className="h-3 w-3" />
</Button>
<Button
variant="ghost"
variant="secondary"
size="sm"
onClick={() => scrollToGroup(timelineGroups.length - 1)}
disabled={timelineGroups.length <= 1}
Expand Down
22 changes: 11 additions & 11 deletions hindsight-control-plane/src/components/document-chunk-modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -94,23 +94,23 @@ export function DocumentChunkModal({ type, id, onClose }: DocumentChunkModalProp
<div className="text-xs font-bold text-muted-foreground uppercase mb-1">
Document ID
</div>
<div className="text-sm font-mono break-all">{data.id}</div>
<div className="text-sm font-mono break-all text-foreground">{data.id}</div>
</div>
{data.created_at && (
<div className="grid grid-cols-2 gap-3">
<div className="p-3 bg-muted rounded-lg">
<div className="text-xs font-bold text-muted-foreground uppercase mb-1">
Created
</div>
<div className="text-sm">
<div className="text-sm text-foreground">
{new Date(data.created_at).toLocaleString()}
</div>
</div>
<div className="p-3 bg-muted rounded-lg">
<div className="text-xs font-bold text-muted-foreground uppercase mb-1">
Memory Units
</div>
<div className="text-sm">{data.memory_unit_count}</div>
<div className="text-sm text-foreground">{data.memory_unit_count}</div>
</div>
</div>
)}
Expand All @@ -119,7 +119,7 @@ export function DocumentChunkModal({ type, id, onClose }: DocumentChunkModalProp
<div className="text-xs font-bold text-muted-foreground uppercase mb-1">
Text Length
</div>
<div className="text-sm">
<div className="text-sm text-foreground">
{data.original_text.length.toLocaleString()} characters
</div>
</div>
Expand All @@ -132,7 +132,7 @@ export function DocumentChunkModal({ type, id, onClose }: DocumentChunkModalProp
Original Text
</div>
<div className="p-4 bg-muted rounded-lg border border-border max-h-[300px] overflow-y-auto">
<pre className="text-sm whitespace-pre-wrap font-mono">
<pre className="text-sm whitespace-pre-wrap font-mono text-foreground">
{data.original_text}
</pre>
</div>
Expand All @@ -146,7 +146,7 @@ export function DocumentChunkModal({ type, id, onClose }: DocumentChunkModalProp
<div className="text-xs font-bold text-muted-foreground uppercase mb-1">
Chunk ID
</div>
<div className="text-sm font-mono break-all">
<div className="text-sm font-mono break-all text-foreground">
{data.chunk_id}
</div>
</div>
Expand All @@ -155,23 +155,23 @@ export function DocumentChunkModal({ type, id, onClose }: DocumentChunkModalProp
<div className="text-xs font-bold text-muted-foreground uppercase mb-1">
Document ID
</div>
<div className="text-sm font-mono break-all">
<div className="text-sm font-mono break-all text-foreground">
{data.document_id}
</div>
</div>
<div className="p-3 bg-muted rounded-lg">
<div className="text-xs font-bold text-muted-foreground uppercase mb-1">
Chunk Index
</div>
<div className="text-sm">{data.chunk_index}</div>
<div className="text-sm text-foreground">{data.chunk_index}</div>
</div>
</div>
{data.created_at && (
<div className="p-3 bg-muted rounded-lg">
<div className="text-xs font-bold text-muted-foreground uppercase mb-1">
Created
</div>
<div className="text-sm">
<div className="text-sm text-foreground">
{new Date(data.created_at).toLocaleString()}
</div>
</div>
Expand All @@ -181,7 +181,7 @@ export function DocumentChunkModal({ type, id, onClose }: DocumentChunkModalProp
<div className="text-xs font-bold text-muted-foreground uppercase mb-1">
Text Length
</div>
<div className="text-sm">
<div className="text-sm text-foreground">
{data.chunk_text.length.toLocaleString()} characters
</div>
</div>
Expand All @@ -194,7 +194,7 @@ export function DocumentChunkModal({ type, id, onClose }: DocumentChunkModalProp
Chunk Text
</div>
<div className="p-4 bg-muted rounded-lg border border-border max-h-[300px] overflow-y-auto">
<pre className="text-sm whitespace-pre-wrap font-mono">
<pre className="text-sm whitespace-pre-wrap font-mono text-foreground">
{data.chunk_text}
</pre>
</div>
Expand Down
Loading
Loading