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
224 changes: 0 additions & 224 deletions .github/workflows/ci.yml

This file was deleted.

2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ See:

- [docs/api-contract.md](docs/api-contract.md) — frozen `/v1` HTTP contract
and the API↔worker Redis protocol.
- [docs/deployment.md](docs/deployment.md) — production runbook.
- [docs/deployment.md](docs/deployment.md) — production runbook (Compose, Helm, Terraform).
- [docs/architecture.md](docs/architecture.md) and
[docs/data-model.md](docs/data-model.md) — runtime topology and database
model.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.agentflow.api.dto;

import com.fasterxml.jackson.annotation.JsonIgnore;
import io.agentflow.api.entity.MessageEntity;
import java.time.Instant;
import java.util.List;
Expand All @@ -17,8 +18,15 @@ public class ThreadMessageResponse {
private String toolCallId;
private Map<String, Object> extra;
private Instant createdAt;
/** Sort key for thread transcript cursors (run.created_at). */
private Instant runCreatedAt;

public static ThreadMessageResponse from(MessageEntity entity, String runId) {
return from(entity, runId, null);
}

public static ThreadMessageResponse from(
MessageEntity entity, String runId, Instant runCreatedAt) {
ThreadMessageResponse dto = new ThreadMessageResponse();
dto.id = entity.getId();
dto.runId = runId;
Expand All @@ -30,6 +38,7 @@ public static ThreadMessageResponse from(MessageEntity entity, String runId) {
dto.toolCallId = entity.getToolCallId();
dto.extra = entity.getExtra();
dto.createdAt = entity.getCreatedAt();
dto.runCreatedAt = runCreatedAt;
return dto;
}

Expand Down Expand Up @@ -73,6 +82,11 @@ public Instant getCreatedAt() {
return createdAt;
}

@JsonIgnore
public Instant getRunCreatedAt() {
return runCreatedAt;
}

public static class Page {
private final List<ThreadMessageResponse> items;
private final String nextCursor;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package io.agentflow.api.repository;

import io.agentflow.api.entity.MessageEntity;
import java.time.Instant;
import java.util.List;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

public interface MessageRepository extends JpaRepository<MessageEntity, String> {

Expand All @@ -14,6 +17,42 @@ public interface MessageRepository extends JpaRepository<MessageEntity, String>
List<MessageEntity> findByRunIdAndIndexLessThanOrderByIndexDesc(
String runId, int index, Pageable pageable);

/**
* Thread transcript rows as {@code [MessageEntity, RunEntity]} ordered
* newest-first for limit-based paging.
*/
@Query(
"""
SELECT m, r FROM MessageEntity m, RunEntity r
WHERE m.runId = r.id AND r.threadId = :threadId
ORDER BY r.createdAt DESC, m.index DESC, m.id DESC
""")
List<Object[]> findThreadMessagesNewestFirst(
@Param("threadId") String threadId, Pageable pageable);

/**
* Messages older than the opaque cursor {@code (runCreatedAt, index, id)},
* still newest-first within that older window.
*/
@Query(
"""
SELECT m, r FROM MessageEntity m, RunEntity r
WHERE m.runId = r.id AND r.threadId = :threadId
AND (
r.createdAt < :cursorCreated
OR (r.createdAt = :cursorCreated AND m.index < :cursorIndex)
OR (r.createdAt = :cursorCreated AND m.index = :cursorIndex
AND m.id < :cursorId)
)
ORDER BY r.createdAt DESC, m.index DESC, m.id DESC
""")
List<Object[]> findThreadMessagesOlderThan(
@Param("threadId") String threadId,
@Param("cursorCreated") Instant cursorCreated,
@Param("cursorIndex") int cursorIndex,
@Param("cursorId") String cursorId,
Pageable pageable);

long deleteByRunId(String runId);

long deleteByRunIdIn(Iterable<String> runIds);
Expand Down
Loading
Loading