Skip to content
Open
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
12 changes: 12 additions & 0 deletions src-tauri/.cargo/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,15 @@ rustflags = [
#
# [target.aarch64-apple-darwin]
# rustflags = ["-C", "link-arg=-fuse-ld=/opt/homebrew/bin/ld64.lld"]

# ── ts-rs codegen: large-int binding ─────────────────────────────────────────
# ts-rs (optional, feature-gated `ts-rs`) maps i64/u64/i128/u128 to `bigint` by
# default. The frontend cross-end contract (hand-written Zod) uses `number`, and
# every ORGII i64 field in practice (token counts, ms timestamps, byte sizes,
# row counts) stays well under Number.MAX_SAFE_INTEGER (2^53). Emit `number`
# globally so generated TS matches the existing wire contract with zero
# per-field annotations. Fields that genuinely need full 64-bit range can opt
# back per-field via `#[ts(type = "bigint")]`. Only consumed by ts-rs
# generation (feature on); no effect on normal builds.
[env]
TS_RS_LARGE_INT = "number"
24 changes: 24 additions & 0 deletions src-tauri/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions src-tauri/crates/session-persistence/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,7 @@ tracing = "0.1"

# Error derive macros — `IntentError` in `turn_intents`.
thiserror = { workspace = true }
ts-rs = { version = "12.0.1", optional = true }

[features]
ts-rs = ["dep:ts-rs"]
10 changes: 10 additions & 0 deletions src-tauri/crates/session-persistence/bindings/CacheStats.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.

/**
* Cache statistics
*/
export type CacheStats = {
totalSessions: number;
totalEvents: number;
dbSizeBytes: number;
};
1 change: 1 addition & 0 deletions src-tauri/crates/session-persistence/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ pub struct CrossSessionSearchHit {

/// Cache statistics
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS), ts(export))]
#[serde(rename_all = "camelCase")]
pub struct CacheStats {
pub total_sessions: i64,
Expand Down
4 changes: 4 additions & 0 deletions src-tauri/crates/transport/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,11 @@ serde = { version = "1.0", features = ["derive"] }
serde_json = "1"
tauri = { workspace = true }
tokio = { workspace = true }
ts-rs = { version = "12.0.1", optional = true }

[dev-dependencies]
tokio = { workspace = true }
chrono = { workspace = true }

[features]
ts-rs = ["dep:ts-rs"]
52 changes: 52 additions & 0 deletions src-tauri/crates/transport/bindings/AgentEvent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.

/**
* Agent event types for session lifecycle
*/
export type AgentEvent =
| {
type: "sessionCreated";
payload: {
sessionId: string;
sessionName: string;
agentType: string;
workspacePath: string | null;
};
}
| { type: "sessionDeleted"; payload: { sessionId: string } }
| {
type: "dialogTurnStarted";
payload: {
sessionId: string;
turnId: string;
turnIndex: number;
userInput: string;
};
}
| {
type: "dialogTurnCompleted";
payload: { sessionId: string; turnId: string };
}
| {
type: "dialogTurnCancelled";
payload: { sessionId: string; turnId: string };
}
| {
type: "dialogTurnFailed";
payload: { sessionId: string; turnId: string; error: string };
}
| {
type: "tokenUsageUpdated";
payload: {
sessionId: string;
turnId: string;
modelId: string;
inputTokens: number;
outputTokens: number;
totalTokens: number;
};
}
| {
type: "sessionStateChanged";
payload: { sessionId: string; newState: string };
};
14 changes: 14 additions & 0 deletions src-tauri/crates/transport/bindings/TextChunk.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.

/**
* Text chunk data structure for streaming
*/
export type TextChunk = {
sessionId: string;
turnId: string;
roundId: string;
text: string;
timestamp: number;
contentType: string | null;
isComplete: boolean;
};
17 changes: 17 additions & 0 deletions src-tauri/crates/transport/bindings/ToolEvent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { ToolEventType } from "./ToolEventType";

/**
* Tool event for tracking tool execution
*/
export type ToolEvent = {
sessionId: string;
turnId: string;
toolId: string;
toolName: string;
eventType: ToolEventType;
params: unknown;
result: unknown;
error: string | null;
durationMs: number | null;
};
14 changes: 14 additions & 0 deletions src-tauri/crates/transport/bindings/ToolEventType.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.

/**
* Tool event types
*/
export type ToolEventType =
| "started"
| "params_detected"
| "params_complete"
| "completed"
| "failed"
| "progress"
| "stream_chunk"
| "confirmation_needed";
129 changes: 7 additions & 122 deletions src-tauri/crates/transport/src/adapters/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,138 +60,23 @@ impl MockTransportAdapter {
#[async_trait]
impl TransportAdapter for MockTransportAdapter {
async fn emit_agent_event(&self, session_id: &str, event: AgentEvent) -> anyhow::Result<()> {
let (event_name, payload) = match event {
AgentEvent::SessionCreated {
session_id: sid,
session_name,
agent_type,
workspace_path,
} => (
"agent://session-created",
serde_json::json!({
"sessionId": sid,
"sessionName": session_name,
"agentType": agent_type,
"workspacePath": workspace_path,
}),
),
AgentEvent::SessionDeleted { session_id: sid } => (
"agent://session-deleted",
serde_json::json!({
"sessionId": sid,
}),
),
AgentEvent::DialogTurnStarted {
session_id: sid,
turn_id,
turn_index,
user_input,
} => (
"agent://dialog-turn-started",
serde_json::json!({
"sessionId": sid,
"turnId": turn_id,
"turnIndex": turn_index,
"userInput": user_input,
}),
),
AgentEvent::DialogTurnCompleted {
session_id: sid,
turn_id,
} => (
"agent://dialog-turn-completed",
serde_json::json!({
"sessionId": sid,
"turnId": turn_id,
}),
),
AgentEvent::DialogTurnCancelled {
session_id: sid,
turn_id,
} => (
"agent://dialog-turn-cancelled",
serde_json::json!({
"sessionId": sid,
"turnId": turn_id,
}),
),
AgentEvent::DialogTurnFailed {
session_id: sid,
turn_id,
error,
} => (
"agent://dialog-turn-failed",
serde_json::json!({
"sessionId": sid,
"turnId": turn_id,
"error": error,
}),
),
AgentEvent::TokenUsageUpdated {
session_id: sid,
turn_id,
model_id,
input_tokens,
output_tokens,
total_tokens,
} => (
"agent://token-usage-updated",
serde_json::json!({
"sessionId": sid,
"turnId": turn_id,
"modelId": model_id,
"inputTokens": input_tokens,
"outputTokens": output_tokens,
"totalTokens": total_tokens,
}),
),
AgentEvent::SessionStateChanged {
session_id: sid,
new_state,
} => (
"agent://session-state-changed",
serde_json::json!({
"sessionId": sid,
"newState": new_state,
}),
),
};

self.capture_event(event_name, payload, session_id).await;
// Mirror the Tauri adapter: serialize the typed event straight to the
// wire so the mock captures exactly what production emits.
let payload = serde_json::to_value(&event)?;
self.capture_event("agent://event", payload, session_id)
.await;
Ok(())
}

async fn emit_text_chunk(&self, session_id: &str, chunk: TextChunk) -> anyhow::Result<()> {
let payload = serde_json::json!({
"sessionId": chunk.session_id,
"turnId": chunk.turn_id,
"roundId": chunk.round_id,
"text": chunk.text,
"timestamp": chunk.timestamp,
"contentType": chunk.content_type,
"isComplete": chunk.is_complete,
});

let payload = serde_json::to_value(&chunk)?;
self.capture_event("agent://text-chunk", payload, session_id)
.await;
Ok(())
}

async fn emit_tool_event(&self, session_id: &str, event: ToolEvent) -> anyhow::Result<()> {
let payload = serde_json::json!({
"sessionId": event.session_id,
"turnId": event.turn_id,
"toolEvent": {
"tool_id": event.tool_id,
"tool_name": event.tool_name,
"event_type": event.event_type,
"params": event.params,
"result": event.result,
"error": event.error,
"duration_ms": event.duration_ms,
}
});

let payload = serde_json::to_value(&event)?;
self.capture_event("agent://tool-event", payload, session_id)
.await;
Ok(())
Expand Down
Loading
Loading