Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
142 commits
Select commit Hold shift + click to select a range
40f9291
Merge pull request #1 from AperturePlus/develop
AperturePlus Mar 20, 2026
61a2eb0
Merge pull request #2 from AperturePlus/develop
AperturePlus Mar 21, 2026
d134bda
Merge pull request #3 from AperturePlus/develop
AperturePlus Mar 21, 2026
103533f
Merge pull request #4 from AperturePlus/develop
AperturePlus Mar 27, 2026
f540acc
Merge pull request #5 from AperturePlus/develop
AperturePlus Mar 28, 2026
2b7749f
Merge pull request #6 from AperturePlus/develop
AperturePlus Mar 29, 2026
05a1374
Merge pull request #7 from AperturePlus/develop
AperturePlus Apr 1, 2026
4dc44c6
Merge pull request #8 from AperturePlus/develop
AperturePlus Apr 22, 2026
ede5010
Merge pull request #11 from AperturePlus/develop
AperturePlus May 10, 2026
cd08983
Merge pull request #12 from AperturePlus/develop
AperturePlus May 12, 2026
8f3ca61
Merge pull request #16 from AperturePlus/develop
AperturePlus May 21, 2026
b7eb448
changed lauch script
AperturePlus May 22, 2026
5c3ff38
removed mock notification
AperturePlus May 22, 2026
add1994
remove deprecated logo elements
AperturePlus May 22, 2026
3a5b66d
readme
AperturePlus May 22, 2026
5eb17fe
feat(web): add i18n messages for agent v2 and file preview
AperturePlus May 23, 2026
508189b
feat(web): extract video preview from FileDetailPanel into dedicated …
AperturePlus May 23, 2026
e9a8359
feat(web): integrate i18n into agent organisms
AperturePlus May 23, 2026
0058840
feat(web): integrate i18n into agent pages (AgentLayout, AgentSkills)
AperturePlus May 23, 2026
8594eaf
docs(spec): add admin console full-stack redesign design
AperturePlus May 24, 2026
091b6f7
docs(plans): add admin console backend (Plan A) and frontend (Plan B)…
AperturePlus May 24, 2026
02d95de
feat(web): align api+mock with Plan A admin contracts
AperturePlus May 24, 2026
a4a4cad
feat(web): scaffold Console layout, sidebar, and 9 subpage routes
AperturePlus May 24, 2026
4846456
feat(web): add Console shared components
AperturePlus May 24, 2026
03c1165
feat(web): Console Overview page
AperturePlus May 24, 2026
68f133d
feat(web): Console Users page
AperturePlus May 24, 2026
c34cdb8
feat(web): Console Storage page with trend and quota editing
AperturePlus May 24, 2026
0b12217
feat(web): Console Content audit page
AperturePlus May 24, 2026
89305c9
feat(web): Console Moderation page
AperturePlus May 24, 2026
79bff83
feat(web): Console System page
AperturePlus May 24, 2026
cc8326d
feat(web): Console Logs page
AperturePlus May 24, 2026
15feac3
feat(web): Console Notifications page with broadcast
AperturePlus May 24, 2026
db4e746
feat(web): Console Rules page (registration email domains)
AperturePlus May 24, 2026
518414e
feat(web): wire Console into MainLayout, drop legacy Dashboard, i18n
AperturePlus May 24, 2026
005d7aa
feat(admin): scaffold admin packages and user status mapping
AperturePlus May 24, 2026
51f8b11
feat(admin): users service with list and set_status (last-admin guard)
AperturePlus May 24, 2026
af44fd9
feat(admin): /admin/users list + /admin/users/{id}/status routes
AperturePlus May 24, 2026
7c4d665
FIX viewerjs type error
AperturePlus May 24, 2026
4d0a3c5
feat(admin): /admin/storage summary, users, quota, usage-trend
AperturePlus May 24, 2026
f5b92f7
feat(admin): /admin/files list + /admin/files/{id}/rescan with event
AperturePlus May 24, 2026
915c131
feat(admin): /admin/violations list + resolve via ModerationCase
AperturePlus May 24, 2026
6ac141f
feat(admin): /admin/logs list with filters
AperturePlus May 24, 2026
3bc3688
feat(admin): /admin/notifications list, broadcast, archive
AperturePlus May 24, 2026
4b4adfb
feat(admin): /admin/system health and rate-limit
AperturePlus May 24, 2026
aa1b760
feat(upload): add backend cancel-upload-session endpoint
AperturePlus May 24, 2026
d6ce680
feat(upload): add frontend cancel types, api, and mock
AperturePlus May 24, 2026
89469c8
refactor(upload): add AbortSignal support to hash and uploader utils
AperturePlus May 24, 2026
a978b85
feat(upload): create Pinia upload store with cancel support
AperturePlus May 24, 2026
6fbf985
feat(upload): integrate cancel into components and composable
AperturePlus May 24, 2026
430215d
test(upload): add backend tests for cancel session
AperturePlus May 24, 2026
921205e
feat(upload): add backend recoverable-sessions endpoint
AperturePlus May 24, 2026
fc67161
feat(upload): add frontend types, api, and mock for recoverable uploads
AperturePlus May 24, 2026
cb5c830
feat(upload): add completeUploadSession and onFileHashed to uploader
AperturePlus May 24, 2026
7ba9556
feat(upload): add i18n keys for resume, paused, and session-expired
AperturePlus May 24, 2026
677d00c
feat(upload): add persistence, recovery, and resume to Pinia upload s…
AperturePlus May 24, 2026
7c6f39f
feat(upload): add paused/resume UI to UploadProgressTray component
AperturePlus May 24, 2026
54eaf40
feat(upload): wire resumeUpload into composable and MyFiles page
AperturePlus May 24, 2026
90bd356
Merge pull request #17 from AperturePlus/feat/agentic
AperturePlus May 24, 2026
38524cc
feat(sharing): batch-apply collaborator/permission changes on Done + …
AperturePlus May 24, 2026
ef252f5
feat(storage): reactive storage stats with auto-refresh on file-tree …
AperturePlus May 24, 2026
f0891cc
chore(config): add upload_verify_merged_object_hash toggle, bump sing…
AperturePlus May 24, 2026
bdb1a81
feat(admin): wire hash_computation_enabled to upload_verify_merged_ob…
AperturePlus May 24, 2026
a3294d6
feat(transcode): force stereo audio output + deterministic ffmpeg err…
AperturePlus May 24, 2026
4d8c19c
feat(ui): add showCancelButton option to PromptDialog + auto-select r…
AperturePlus May 24, 2026
28b201e
feat(preview): add signed preview URL endpoint for video streaming
AperturePlus May 24, 2026
34e9628
feat(stream): add ResolvedStreamObject with transcode MIME content-ty…
AperturePlus May 24, 2026
181bd61
feat(upload): make merged-object hash verification conditional on set…
AperturePlus May 24, 2026
f725409
refactor(uploader): extract hash chunk size constants and add backend…
AperturePlus May 24, 2026
4872391
test(upload): add refresh-file-tree emit test and new spec files
AperturePlus May 24, 2026
1637822
feat(config): add DEFAULT_ADMIN_* env vars for production bootstrap
AperturePlus May 25, 2026
84cebf2
feat(seed): support production admin account seeding from env vars
AperturePlus May 25, 2026
3679031
test(settings): add production admin env validation tests
AperturePlus May 25, 2026
d8db5de
test(seed): add production admin account seeding test
AperturePlus May 25, 2026
bb3ec08
test(startup): add fail-fast tests for production admin env validation
AperturePlus May 25, 2026
3844c57
Merge pull request #18 from AperturePlus/feat/agentic
AperturePlus May 25, 2026
43c27ee
.env
AperturePlus May 25, 2026
322b2d2
refactor(agent): move AgentLayout from pages to templates with tab na…
AperturePlus May 25, 2026
421fdda
feat(layout): add fullscreen mode for agent routes
AperturePlus May 25, 2026
4f96b15
Merge pull request #19 from AperturePlus/feat/agentic
AperturePlus May 25, 2026
d2cc812
feat(security): add admin file preview token create/decode helpers
AperturePlus May 25, 2026
2342ce9
feat(schemas): add AdminFileAuditDetail, AdminFileAuditOwner, AdminFi…
AperturePlus May 25, 2026
e030c5f
feat(services): add admin file detail aggregation and preview streami…
AperturePlus May 25, 2026
7e950a2
feat(routers): add admin file detail, preview, preview-url, preview-s…
AperturePlus May 25, 2026
ab830d9
test(admin): add tests for admin file detail, preview streaming, prev…
AperturePlus May 25, 2026
ad13f26
feat(types): add AdminFileAuditDetail, AdminFileLatestScan, AdminFile…
AperturePlus May 25, 2026
64700ed
feat(api): add getAdminFileDetail, previewAdminFile, getAdminPreviewU…
AperturePlus May 25, 2026
e9d0b75
feat(mock): add admin file detail, preview, preview-url mock handlers…
AperturePlus May 25, 2026
4d69401
feat(components): add prop injection pattern for preview/download loa…
AperturePlus May 25, 2026
2499db2
feat(console): add file detail panel, owner list, and preview dialog …
AperturePlus May 25, 2026
4167db6
chore: remove empty exceptions __init__.py
AperturePlus May 25, 2026
2a7d766
Merge pull request #20 from AperturePlus/feat/audit
AperturePlus May 25, 2026
8c0181b
feat(agent): add agent schemas, API routes, and layer init exports
AperturePlus May 25, 2026
2bb1171
feat(agent): implement plan_runner and execute_runner runtime
AperturePlus May 25, 2026
cdf6f42
feat(agent): implement policy guard and tool router harness
AperturePlus May 25, 2026
b93befc
feat(agent): add LLM planner client and agent worker process
AperturePlus May 25, 2026
b4c5916
feat(agent): add plan and execute services with background job support
AperturePlus May 25, 2026
1de1fd7
feat(agent): configure agent settings, DI wiring, and dependencies
AperturePlus May 25, 2026
8445e5e
fix(agent): use BIGINT cast for user_id in repository queries
AperturePlus May 25, 2026
7089bcc
feat(agent): add agent worker process management to run_with_workers
AperturePlus May 25, 2026
5fd69c3
feat(agent): add builtin skill migration and backend tests
AperturePlus May 25, 2026
fff008c
feat(web): wire AgentReasoningEffort and high-risk confirmation acros…
AperturePlus May 25, 2026
b3e3b45
test(web): add missing file-api mocks to test specs
AperturePlus May 25, 2026
1b729fb
feat(agent): add symbolic placeholder validation in plan and execute …
AperturePlus May 25, 2026
4b07b0f
fix(agent): normalize datetime and non-serializable types in tool rou…
AperturePlus May 25, 2026
6b7f1c6
test(agent): add tests for placeholder validation and datetime serial…
AperturePlus May 25, 2026
5014c91
fix(web): surface backend error messages from agent execute/plan/canc…
AperturePlus May 25, 2026
383ccce
Merge pull request #21 from AperturePlus/feat/audit
AperturePlus May 25, 2026
11fb3d6
fix(agent): prevent duplicate execute for same plan via idempotency k…
AperturePlus May 25, 2026
b8b827d
feat(web): add viewport-aware smart placement to Select dropdown
AperturePlus May 25, 2026
be17bd9
feat(web): hide Execute button on TurnEntry once executeJobId is assi…
AperturePlus May 25, 2026
c48bb16
fix(web): add no-op early-return guards to runExecute
AperturePlus May 25, 2026
0c91487
feat(agent): add drive.countFiles tool with categorization and execut…
AperturePlus May 25, 2026
0c927bd
test(agent): add tests for countFiles tool, LLM retry, fallback, canc…
AperturePlus May 25, 2026
41ac265
refactor(web): rewrite polling to generation-based loop with cancel s…
AperturePlus May 25, 2026
85eb326
test(web): add tests for cancel safety, auto-execute read-only plans,…
AperturePlus May 25, 2026
f68fb87
feat(web): wire execution answer display, i18n confirm dialogs, and c…
AperturePlus May 25, 2026
b17a7c9
fix(web): normalize storagePercentage ratio in (0,1] and update typog…
AperturePlus May 25, 2026
28a4abb
Merge pull request #22 from AperturePlus/feat/audit
AperturePlus May 25, 2026
58d4554
feat(agent): add search term support to drive.countFiles tool
AperturePlus May 26, 2026
baa3a16
feat(agent): add SSE event streaming for agent job lifecycle
AperturePlus May 26, 2026
80b88bd
feat(web): render agent activity events in TurnEntry component
AperturePlus May 26, 2026
e3f9744
feat(admin): add usage statistics to admin users panel
AperturePlus May 26, 2026
394ba18
feat: add download rate limiting with user and IP tracking
AperturePlus May 26, 2026
87c935f
docs(agent): spec for agent subsystem improvements (interaction, sess…
AperturePlus May 26, 2026
0d87046
docs(agent): implementation plan for subproject A (interaction layer,…
AperturePlus May 26, 2026
b1ba1c9
docs(agent): implementation plan for subproject A (interaction layer,…
AperturePlus May 26, 2026
604d6ce
feat(agent): add inbox foundation — settings, enums, model, V14 migra…
AperturePlus May 26, 2026
1ae2b4e
feat(agent): add ToolRegistry and EventBus core services
AperturePlus May 26, 2026
cd30f57
refactor(agent): use ToolRegistry in policy, router, deps, and skill …
AperturePlus May 26, 2026
50c2c1d
feat(agent): add AgentInbox, AskProtocol, and POST /agent/jobs/{id}/m…
AperturePlus May 26, 2026
967d7a1
feat(agent): wire runners and worker with EventBus, inbox controls, L…
AperturePlus May 26, 2026
7ba35c9
feat(web): add agent interaction frontend — inbox controls, ask/reply…
AperturePlus May 26, 2026
6f7b200
docs: fix markdown formatting in implementation plans
AperturePlus May 26, 2026
c2dab2b
feat(auth): adjust risk-control default thresholds
AperturePlus May 26, 2026
53f5546
feat(agent): add planning evidence tracking and grounded write summary
AperturePlus May 26, 2026
5182a5d
feat(web): display planning evidence in agent turn entry
AperturePlus May 26, 2026
51a8b34
Merge pull request #23 from AperturePlus/feat/audit
AperturePlus May 26, 2026
aca4119
fix(rate-limiter): handle Redis RuntimeError on loop mismatch, gracef…
AperturePlus May 26, 2026
75d5581
feat(agent): allow unbounded max_steps in dev mode for plan creation …
AperturePlus May 26, 2026
41f7abb
feat(agent): block write tools in planner exploration gracefully with…
AperturePlus May 27, 2026
32a48af
Merge pull request #24 from AperturePlus/feat/audit
AperturePlus May 27, 2026
ebe1c26
feat: add docker deployment config and fix select dropdown
khamkhamini94-bit May 28, 2026
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
48 changes: 48 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# IDE
.idea/
.vscode/
*.swp
*.swo

# Git
.git/
.gitignore
.gitattributes

# Node
web/node_modules/
web/dist/
web/electron/
web/.nuxt/
web/.output/

# Python
app/__pycache__/
app/src/__pycache__/
app/.venv/
app/.uv/
**/*.pyc
**/*.pyo
**/__pycache__/
**/.pytest_cache/
**/.ruff_cache/

# Docker
docker/data/
docker/postgresql-16/data/
docker/redis/data/
docker/minio/data/

# Docs
docs/
/*.md
*.drawio

# Tests
app/tests/
web/src/**/*.test.ts
web/src/**/*.spec.ts

# Misc
.claude/
.superpowers/
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,4 @@ app/artifacts/
.playwright*
.snow/

/node_modules/
/node_modules/docker/.env.production
16 changes: 15 additions & 1 deletion app/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,22 @@ FF_DB_URI=postgresql://root:password@localhost:5432/fileflash
# DATABASE_URL=postgresql://root:password@localhost:5432/fileflash
APP_ENV=development

# Required when APP_ENV=production or APP_ENV=prod.
DEFAULT_ADMIN_USERNAME=administrator
DEFAULT_ADMIN_EMAIL=admin@fileflash.next
DEFAULT_ADMIN_PASSWORD=replace-with-32-bytes-or-longer-password

JWT_SECRET_KEY=please-set-at-least-32-bytes-secret-key
# Optional dedicated HMAC key for token hash persistence.
# Falls back to JWT_SECRET_KEY when omitted.
# TOKEN_HASH_SECRET=please-set-at-least-32-bytes-and-different-from-jwt-secret
ACCESS_TOKEN_EXPIRE_MINUTES=4320
REFRESH_TOKEN_EXPIRE_DAYS=7
# Auth risk-control defaults (can be overridden per environment)
MAX_FAILED_LOGIN_ATTEMPTS=8
ACCOUNT_LOCK_MINUTES=5
REGISTER_RATE_LIMIT=12
LOGIN_RATE_LIMIT=30

REDIS_URL=redis://localhost:6379/0
# RabbitMQ is optional in this stage, kept for future publisher swap.
Expand All @@ -26,6 +36,7 @@ UPLOAD_CHUNK_SIZE_DEFAULT=5242880
UPLOAD_CHUNK_SIZE_MIN=1048576
UPLOAD_CHUNK_SIZE_MAX=16777216
UPLOAD_SINGLE_FILE_SIZE_MAX=5368709120
UPLOAD_VERIFY_MERGED_OBJECT_HASH=false
STARRED_ITEMS_LIMIT=20
UPLOAD_SESSION_TTL_HOURS=24
UPLOAD_TEMP_PREFIX=tmp
Expand Down Expand Up @@ -54,9 +65,12 @@ AGENT_COMPACT_THRESHOLD=0.75
AGENT_USER_DAILY_LIMIT=50
AGENT_USER_CONCURRENT_LIMIT=2
AGENT_STAGING_TTL_SEC=86400
AGENT_SSE_ENABLED=false
AGENT_SSE_ENABLED=true
AGENT_LLM_PROVIDER=anthropic
AGENT_LLM_MODEL=claude-sonnet-4-6
AGENT_LLM_PLAN_MAX_TOKENS=8192
# For Anthropic-compatible providers, e.g. DeepSeek: https://api.deepseek.com/anthropic
# AGENT_LLM_BASE_URL=
# AGENT_LLM_API_KEY=
AGENT_MCP_ENDPOINTS=[]

Expand Down
12 changes: 6 additions & 6 deletions app/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,26 @@
Use one command to start backend API and file workers together:

```bash
uv run python -m fileflash.scripts.run_with_workers
uv run fileflash
```

Common options:

```bash
# custom host/port
uv run python -m fileflash.scripts.run_with_workers --host 127.0.0.1 --port 8080
uv run fileflash --host 127.0.0.1 --port 8080

# start multiple worker processes
uv run python -m fileflash.scripts.run_with_workers --worker-count 2
uv run fileflash --worker-count 2

# API only (without workers)
uv run python -m fileflash.scripts.run_with_workers --no-worker
uv run fileflash --no-worker
```

Notes:
- This runner starts `uvicorn fileflash.main:app` and `python -m fileflash.workers.consumer`.
- If any subprocess exits, the runner stops all other subprocesses.
- If your environment resolves project scripts correctly, `uv run fileflash-dev` is equivalent.
- `uv run fileflash-dev` is kept as a backward-compatible alias.

## Database Migration Requirement

Expand All @@ -31,6 +31,6 @@ Before starting API processes, ensure Flyway migrations are fully applied (inclu
Recommended startup order:
1. Start PostgreSQL
2. Run Flyway migrate
3. Start API (`uv run fileflash`) or runner (`uv run fileflash-dev`)
3. Start backend (`uv run fileflash`; `uv run fileflash-dev` is also supported)

If the schema is outdated, API startup will fail fast with an explicit compatibility error.
5 changes: 3 additions & 2 deletions app/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@ dependencies = [
"sqlalchemy>=2.0.48",
"uvicorn>=0.42.0",
"python-multipart>=0.0.24",
"anthropic>=0.104.1",
]
[project.scripts]
fileflash = "fileflash.main:main"
fileflash = "fileflash.scripts.run_with_workers:main"
fileflash-dev = "fileflash.scripts.run_with_workers:main"

[dependency-groups]
Expand Down Expand Up @@ -50,4 +51,4 @@ requires = ["hatchling"]
build-backend = "hatchling.build"

[tool.hatch.build.targets.wheel]
packages = ["src/fileflash"]
packages = ["src/fileflash"]
3 changes: 2 additions & 1 deletion app/src/fileflash/agents/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@
ToolCall,
ToolRouter,
)
from .runtime import ExecuteRunner, PlanRunner, SubagentRunner
from .runtime import AgentJobCanceled, ExecuteRunner, PlanRunner, SubagentRunner

__all__ = [
"AgentJobCanceled",
"AgentEvent",
"CheckpointStore",
"ContextBudget",
Expand Down
5 changes: 5 additions & 0 deletions app/src/fileflash/agents/harness/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from .policy import PolicyDecision, PolicyGuard
from .prompt import PromptBuildRequest, PromptBuilder
from .router import ToolCall, ToolRouter
from .tool_registry import REGISTRY, ToolContext, ToolRegistry, ToolSpec

__all__ = [
"AgentEvent",
Expand All @@ -20,6 +21,10 @@
"PolicyGuard",
"PromptBuildRequest",
"PromptBuilder",
"REGISTRY",
"ToolCall",
"ToolContext",
"ToolRegistry",
"ToolRouter",
"ToolSpec",
]
128 changes: 128 additions & 0 deletions app/src/fileflash/agents/harness/ask.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
from __future__ import annotations

import asyncio
import contextlib
from datetime import UTC, datetime
from typing import Any

from sqlalchemy.ext.asyncio import AsyncSession

from ...repositories import AgentInboxMessageRepository
from .event_bus import AgentEventBus, AgentEventEnvelope, AgentEventStream


class AskTimedOut(Exception):
def __init__(self, *, ask_id: int) -> None:
super().__init__(f"Ask {ask_id} timed out")
self.ask_id = ask_id


class AskProtocol:
def __init__(
self,
*,
db: AsyncSession,
event_bus: AgentEventBus,
job_id: int,
) -> None:
self._db = db
self._bus = event_bus
self._job_id = job_id
self._repo = AgentInboxMessageRepository(db)
self._waiters: dict[int, asyncio.Future[Any]] = {}
self._sub_ctx = None
self._sub_stream: AgentEventStream | None = None
self._sub_task: asyncio.Task[None] | None = None

async def start(self) -> None:
self._sub_ctx = self._bus.subscribe(job_id=self._job_id)
self._sub_stream = await self._sub_ctx.__aenter__()
self._sub_task = asyncio.create_task(self._listen())

async def aclose(self) -> None:
if self._sub_task is not None:
self._sub_task.cancel()
with contextlib.suppress(asyncio.CancelledError):
await self._sub_task
if self._sub_ctx is not None:
await self._sub_ctx.__aexit__(None, None, None)
for future in self._waiters.values():
if not future.done():
future.cancel()

async def ask(
self,
*,
prompt: str,
schema: dict[str, Any],
timeout_sec: float,
) -> Any:
msg = await self._repo.create_ask(
job_id=self._job_id,
payload={"prompt": prompt, "schema": schema, "timeoutSec": timeout_sec},
)
await self._db.commit()

ask_id = int(msg.inbox_message_id)
loop = asyncio.get_running_loop()
future: asyncio.Future[Any] = loop.create_future()
self._waiters[ask_id] = future

await self._bus.publish(
AgentEventEnvelope(
job_id=self._job_id,
event_type="agent.ask",
payload={
"messageId": str(ask_id),
"prompt": prompt,
"schema": schema,
"timeoutSec": timeout_sec,
},
emitted_at=datetime.now(UTC),
)
)

try:
value = await asyncio.wait_for(future, timeout=timeout_sec)
except TimeoutError as exc:
await self._repo.mark_timed_out(
inbox_message_id=ask_id,
answered_at=datetime.now(UTC),
)
await self._db.commit()
raise AskTimedOut(ask_id=ask_id) from exc
finally:
self._waiters.pop(ask_id, None)

await self._repo.mark_answered(
inbox_message_id=ask_id,
answered_at=datetime.now(UTC),
)
await self._db.commit()
return value

async def _listen(self) -> None:
assert self._sub_stream is not None
while True:
try:
envelope = await self._sub_stream.next(timeout=None)
except asyncio.CancelledError:
raise
except Exception:
continue
if envelope.event_type != "agent.inbox.reply":
continue
reply_to = envelope.payload.get("replyTo")
if reply_to is None:
continue
try:
ask_id = int(reply_to)
except (TypeError, ValueError):
continue
future = self._waiters.get(ask_id)
if future is None or future.done():
continue
future.set_result(envelope.payload.get("value"))


__all__ = ["AskProtocol", "AskTimedOut"]
Loading
Loading