blob: 7b68f9373ee068427cc6251b0a2f76f4088e1ebf [file]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
//! Exact own-source rows from the existing presentation reducer.
use super::{evidence, read};
use crate::StoreError;
use maka_agent_facts::event::{Fact, ToolOutcome};
use maka_presentation::{InvocationView, Row};
use rusqlite::{Connection as RawConnection, OptionalExtension, params};
use sqlx::sqlite::SqliteWorkerConnection;
pub(super) const ELIGIBLE: &str = r#"(e.kind = 'context_checkpoint_recorded' OR NOT EXISTS (SELECT 1 FROM runtime_events opening
WHERE opening.invocation_id = e.invocation_id
AND opening.kind = 'invocation_opened'
AND json_extract(opening.event_json, '$.fact.input.kind') = 'context_compact'))
AND (e.kind NOT IN ('model_completed', 'model_interrupted') OR
EXISTS (SELECT 1 FROM runtime_events request
JOIN runtime_events opening ON opening.invocation_id = request.invocation_id
AND opening.kind = 'invocation_opened'
WHERE request.kind = 'model_requested' AND request.invocation_id = e.invocation_id
AND request.operation_id = e.operation_id
AND json_extract(opening.event_json, '$.fact.input.kind') IN ('message', 'continuation', 'handoff')
AND json_extract(request.event_json, '$.fact.purpose') = 'main'))
AND (e.kind IN ('message_imported', 'invocation_opened', 'message_steered', 'model_completed',
'model_interrupted', 'invocation_ended', 'context_checkpoint_recorded',
'tool_dispatched', 'tool_rejected', 'tool_settled', 'executor_completed')
OR (e.kind = 'model_observed'
AND json_extract(e.event_json, '$.fact.event.kind') IN ('part_finished','source','tool_call','provider_tool_result')
AND json_type(e.event_json, '$.fact.step_id') = 'text'
AND EXISTS (SELECT 1 FROM runtime_events request
JOIN runtime_events opening ON opening.invocation_id = request.invocation_id AND opening.kind = 'invocation_opened'
WHERE request.kind = 'model_requested' AND request.invocation_id = e.invocation_id
AND request.sequence < e.sequence
AND request.operation_id = CAST(json_extract(e.event_json, '$.fact.step_id') AS TEXT)
AND json_extract(e.event_json, '$.fact.step_id') = request.operation_id
AND json_extract(request.event_json, '$.fact.purpose') = 'main'
AND json_extract(request.event_json, '$.fact.item_acceptance') = 1
AND json_extract(opening.event_json, '$.fact.input.kind') IN ('message','continuation','handoff')))
OR (e.kind = 'executor_observed' AND json_extract(e.event_json, '$.fact.output.type') IN ('tool_start','tool_result')))"#;
pub(super) async fn source_on_worker(
connection: &mut SqliteWorkerConnection<'_>,
session: &str,
source: u64,
) -> Result<Vec<Row>, StoreError> {
let sequence = read::sql_number(source)?;
// Reuse the original SQLx statement cache across bounded page callbacks.
// Projection still borrows the same connection and transaction below.
let sql = candidate_sql();
let candidate: Option<(String, Option<String>, String)> =
sqlx::query_as(sqlx::AssertSqlSafe(sql.as_str()))
.bind(sequence)
.bind(session)
.fetch_optional(&mut *connection)
.await?;
let Some(candidate) = candidate else {
return Ok(Vec::new());
};
let (invocation, step, kind) = candidate;
let projection = if kind == "context_checkpoint_recorded" {
Projection::Compaction
} else {
Projection::Evidence(
evidence::selected_on_worker(connection, &invocation, step.as_deref(), sequence, true)
.await?,
)
};
// SAFETY: exclusive worker-local borrow; no handle-backed values escape.
let db = unsafe { RawConnection::from_handle(connection.as_raw_handle().as_ptr()) }?;
db.set_prepared_statement_cache_capacity(100);
project_source(&db, session, sequence, projection)
}
fn candidate_sql() -> String {
format!(
"SELECT e.invocation_id, CASE WHEN e.kind = 'model_observed' THEN json_extract(e.event_json, '$.fact.step_id') ELSE e.operation_id END, e.kind FROM runtime_events e WHERE e.sequence = ?1 AND (e.event_session = ?2 OR EXISTS(SELECT 1 FROM session_history_members h WHERE h.session_id = ?2 AND h.sequence = e.sequence)) AND {ELIGIBLE}"
)
}
pub(super) fn source_on_handle(
db: &RawConnection,
session: &str,
source: i64,
) -> Result<Vec<Row>, StoreError> {
let sql = candidate_sql();
let candidate: Option<(String, Option<String>, String)> = db
.prepare_cached(&sql)?
.query_row(params![source, session], |row| {
Ok((row.get(0)?, row.get(1)?, row.get(2)?))
})
.optional()?;
let Some((invocation, step, kind)) = candidate else {
return Ok(Vec::new());
};
let projection = if kind == "context_checkpoint_recorded" {
Projection::Compaction
} else {
Projection::Evidence(evidence::selected_on_handle(
db,
&invocation,
step.as_deref(),
source,
true,
)?)
};
project_source(db, session, source, projection)
}
enum Projection {
Compaction,
Evidence(Vec<i64>),
}
fn project_source(
db: &RawConnection,
session: &str,
source: i64,
projection: Projection,
) -> Result<Vec<Row>, StoreError> {
let ids = match projection {
Projection::Compaction => return Ok(vec![super::compaction::project(db, source)?]),
Projection::Evidence(ids) => ids,
};
let mut view = InvocationView::new();
let mut own = Vec::new();
for sequence in ids {
let fact = evidence::fact_on_handle(db, sequence)?;
let resolved = if let Fact::ToolSettled {
outcome: ToolOutcome::Succeeded { .. },
..
} = &fact.event.fact
{
Some(crate::tool_payloads::resolve_in_transaction(
db,
&fact.event,
)?)
} else {
None
};
for mut row in view.push_with_tool_output(&fact, resolved.as_ref())? {
if fact.event.invocation.session_id != session {
owned_references(db, session, &mut row.message)?;
}
if row.position.source_sequence == source as u64 {
own.push(row);
}
}
}
Ok(own)
}
fn owned_references(
db: &RawConnection,
session: &str,
message: &mut maka_presentation::Message,
) -> Result<(), StoreError> {
use maka_agent_facts::attachment::StorageRef;
use maka_presentation::{Content, ToolContent};
let refs: Vec<_> = match &mut message.content {
Content::User { attachments, .. } => attachments
.iter_mut()
.flatten()
.map(|a| &mut a.storage_ref)
.collect(),
Content::ToolResult {
content: ToolContent::Image { reference, .. },
..
} => vec![reference],
_ => Vec::new(),
};
for reference in refs {
if let StorageRef::SessionFile {
session_id,
relative_path,
} = reference
{
let id: Option<String> = db
.prepare_cached(crate::artifacts::history::RESOLVE_SQL)?
.query_row(params![session, &*session_id, &*relative_path], |row| {
row.get(0)
})
.optional()?;
*reference = id
.map(|relative_path| StorageRef::SessionFile {
session_id: session.into(),
relative_path,
})
.ok_or(StoreError::TranscriptConflict)?;
}
}
Ok(())
}