flock-core 0.4.0b50__py3-none-any.whl → 0.4.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of flock-core might be problematic. Click here for more details.
- flock/adapter/__init__.py +14 -0
- flock/adapter/azure_adapter.py +68 -0
- flock/adapter/chroma_adapter.py +73 -0
- flock/adapter/faiss_adapter.py +97 -0
- flock/adapter/pinecone_adapter.py +51 -0
- flock/adapter/vector_base.py +47 -0
- flock/cli/constants.py +1 -1
- flock/config.py +1 -1
- flock/core/context/context.py +20 -0
- flock/core/flock.py +71 -91
- flock/core/flock_agent.py +58 -3
- flock/core/flock_module.py +5 -0
- flock/core/util/cli_helper.py +1 -1
- flock/di.py +41 -0
- flock/modules/enterprise_memory/README.md +99 -0
- flock/modules/enterprise_memory/enterprise_memory_module.py +526 -0
- flock/modules/mem0/mem0_module.py +79 -16
- flock/modules/mem0_async/async_mem0_module.py +126 -0
- flock/modules/memory/memory_module.py +28 -8
- flock/modules/performance/metrics_module.py +24 -1
- flock/modules/zep/__init__.py +1 -0
- flock/modules/zep/zep_module.py +192 -0
- flock/webapp/app/api/execution.py +79 -2
- flock/webapp/app/chat.py +83 -3
- flock/webapp/app/services/sharing_models.py +38 -0
- flock/webapp/app/services/sharing_store.py +60 -1
- flock/webapp/static/css/chat.css +2 -0
- flock/webapp/templates/partials/_chat_messages.html +50 -4
- flock/webapp/templates/partials/_results_display.html +39 -0
- {flock_core-0.4.0b50.dist-info → flock_core-0.4.2.dist-info}/METADATA +5 -7
- {flock_core-0.4.0b50.dist-info → flock_core-0.4.2.dist-info}/RECORD +35 -24
- flock/modules/mem0graph/mem0_graph_module.py +0 -63
- /flock/modules/{mem0graph → mem0_async}/__init__.py +0 -0
- {flock_core-0.4.0b50.dist-info → flock_core-0.4.2.dist-info}/WHEEL +0 -0
- {flock_core-0.4.0b50.dist-info → flock_core-0.4.2.dist-info}/entry_points.txt +0 -0
- {flock_core-0.4.0b50.dist-info → flock_core-0.4.2.dist-info}/licenses/LICENSE +0 -0
|
@@ -26,6 +26,7 @@ from flock.core.util.spliter import parse_schema
|
|
|
26
26
|
from flock.webapp.app.dependencies import (
|
|
27
27
|
get_flock_instance,
|
|
28
28
|
get_optional_flock_instance,
|
|
29
|
+
get_shared_link_store,
|
|
29
30
|
)
|
|
30
31
|
|
|
31
32
|
# Service function now takes app_state
|
|
@@ -33,6 +34,7 @@ from flock.webapp.app.services.flock_service import (
|
|
|
33
34
|
run_current_flock_service,
|
|
34
35
|
# get_current_flock_instance IS NO LONGER IMPORTED
|
|
35
36
|
)
|
|
37
|
+
from flock.webapp.app.services.sharing_store import SharedLinkStoreInterface
|
|
36
38
|
|
|
37
39
|
router = APIRouter()
|
|
38
40
|
BASE_DIR = Path(__file__).resolve().parent.parent.parent
|
|
@@ -155,7 +157,16 @@ async def htmx_run_flock(
|
|
|
155
157
|
|
|
156
158
|
return templates.TemplateResponse(
|
|
157
159
|
"partials/_results_display.html",
|
|
158
|
-
{
|
|
160
|
+
{
|
|
161
|
+
"request": request,
|
|
162
|
+
"result": result_data,
|
|
163
|
+
"result_raw_json": result_data_raw_json_str,
|
|
164
|
+
"feedback_endpoint": "/ui/api/flock/htmx/feedback",
|
|
165
|
+
"share_id": None,
|
|
166
|
+
"flock_name": current_flock_from_state.name,
|
|
167
|
+
"agent_name": start_agent_name,
|
|
168
|
+
"flock_definition": current_flock_from_state.to_yaml(),
|
|
169
|
+
}
|
|
159
170
|
)
|
|
160
171
|
|
|
161
172
|
|
|
@@ -218,5 +229,71 @@ async def htmx_run_shared_flock(
|
|
|
218
229
|
|
|
219
230
|
return templates.TemplateResponse(
|
|
220
231
|
"partials/_results_display.html",
|
|
221
|
-
{
|
|
232
|
+
{
|
|
233
|
+
"request": request,
|
|
234
|
+
"result": result_data,
|
|
235
|
+
"result_raw_json": result_data_raw_json_str,
|
|
236
|
+
"feedback_endpoint": "/ui/api/flock/htmx/feedback-shared",
|
|
237
|
+
"share_id": share_id,
|
|
238
|
+
"flock_name": temp_flock.name,
|
|
239
|
+
"agent_name": start_agent_name,
|
|
240
|
+
"flock_definition": temp_flock.to_yaml(),
|
|
241
|
+
}
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
# --- Feedback endpoints ---
|
|
245
|
+
@router.post("/htmx/feedback", response_class=HTMLResponse)
|
|
246
|
+
async def htmx_submit_feedback(
|
|
247
|
+
request: Request,
|
|
248
|
+
reason: str = Form(...),
|
|
249
|
+
expected_response: str | None = Form(None),
|
|
250
|
+
actual_response: str | None = Form(None),
|
|
251
|
+
flock_name: str | None = Form(None),
|
|
252
|
+
agent_name: str | None = Form(None),
|
|
253
|
+
flock_definition: str | None = Form(None),
|
|
254
|
+
store: SharedLinkStoreInterface = Depends(get_shared_link_store),
|
|
255
|
+
):
|
|
256
|
+
from uuid import uuid4
|
|
257
|
+
|
|
258
|
+
from flock.webapp.app.services.sharing_models import FeedbackRecord
|
|
259
|
+
|
|
260
|
+
record = FeedbackRecord(
|
|
261
|
+
feedback_id=uuid4().hex,
|
|
262
|
+
share_id=None,
|
|
263
|
+
context_type="agent_run",
|
|
264
|
+
reason=reason,
|
|
265
|
+
expected_response=expected_response,
|
|
266
|
+
actual_response=actual_response,
|
|
267
|
+
flock_name=flock_name,
|
|
268
|
+
agent_name=agent_name,
|
|
269
|
+
flock_definition=flock_definition,
|
|
270
|
+
)
|
|
271
|
+
await store.save_feedback(record)
|
|
272
|
+
return HTMLResponse("<p>🙏 Feedback received – thank you!</p>")
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
@router.post("/htmx/feedback-shared", response_class=HTMLResponse)
|
|
276
|
+
async def htmx_submit_feedback_shared(
|
|
277
|
+
request: Request,
|
|
278
|
+
share_id: str = Form(...),
|
|
279
|
+
reason: str = Form(...),
|
|
280
|
+
expected_response: str | None = Form(None),
|
|
281
|
+
actual_response: str | None = Form(None),
|
|
282
|
+
flock_definition: str | None = Form(None),
|
|
283
|
+
store: SharedLinkStoreInterface = Depends(get_shared_link_store),
|
|
284
|
+
):
|
|
285
|
+
from uuid import uuid4
|
|
286
|
+
|
|
287
|
+
from flock.webapp.app.services.sharing_models import FeedbackRecord
|
|
288
|
+
|
|
289
|
+
record = FeedbackRecord(
|
|
290
|
+
feedback_id=uuid4().hex,
|
|
291
|
+
share_id=share_id,
|
|
292
|
+
context_type="agent_run",
|
|
293
|
+
reason=reason,
|
|
294
|
+
expected_response=expected_response,
|
|
295
|
+
actual_response=actual_response,
|
|
296
|
+
flock_definition=flock_definition,
|
|
222
297
|
)
|
|
298
|
+
await store.save_feedback(record)
|
|
299
|
+
return HTMLResponse("<p>🙏 Feedback received for shared run – thank you!</p>")
|
flock/webapp/app/chat.py
CHANGED
|
@@ -14,7 +14,10 @@ from flock.core.flock import Flock
|
|
|
14
14
|
from flock.core.logging.logging import get_logger
|
|
15
15
|
from flock.webapp.app.dependencies import get_shared_link_store
|
|
16
16
|
from flock.webapp.app.main import get_base_context_web, templates
|
|
17
|
-
from flock.webapp.app.services.sharing_models import
|
|
17
|
+
from flock.webapp.app.services.sharing_models import (
|
|
18
|
+
FeedbackRecord,
|
|
19
|
+
SharedLinkConfig,
|
|
20
|
+
)
|
|
18
21
|
from flock.webapp.app.services.sharing_store import SharedLinkStoreInterface
|
|
19
22
|
|
|
20
23
|
router = APIRouter()
|
|
@@ -224,7 +227,15 @@ async def chat_send(request: Request, message: str = Form(...)):
|
|
|
224
227
|
# If even echo should be markdown, remove is_error=True here and let it pass through. For now, plain.
|
|
225
228
|
|
|
226
229
|
duration_ms = int((datetime.now() - start_time).total_seconds() * 1000)
|
|
227
|
-
history.append({
|
|
230
|
+
history.append({
|
|
231
|
+
"role": "bot",
|
|
232
|
+
"text": bot_text,
|
|
233
|
+
"timestamp": current_time,
|
|
234
|
+
"agent": bot_agent or "echo",
|
|
235
|
+
"duration_ms": duration_ms,
|
|
236
|
+
"raw_json": original_bot_text if 'original_bot_text' in locals() else bot_text,
|
|
237
|
+
"flock_yaml": getattr(flock_inst, 'to_yaml', lambda: "")()
|
|
238
|
+
})
|
|
228
239
|
# Return updated history partial
|
|
229
240
|
return templates.TemplateResponse(
|
|
230
241
|
"partials/_chat_messages.html",
|
|
@@ -516,9 +527,78 @@ async def chat_send_shared(
|
|
|
516
527
|
bot_text = f"Shared Echo: {message}"
|
|
517
528
|
|
|
518
529
|
duration_ms = int((datetime.now() - start_time).total_seconds() * 1000)
|
|
519
|
-
history.append({
|
|
530
|
+
history.append({
|
|
531
|
+
"role": "bot",
|
|
532
|
+
"text": bot_text,
|
|
533
|
+
"timestamp": current_time,
|
|
534
|
+
"agent": bot_agent or "shared-echo",
|
|
535
|
+
"duration_ms": duration_ms,
|
|
536
|
+
"raw_json": original_bot_text if 'original_bot_text' in locals() else bot_text,
|
|
537
|
+
"flock_yaml": getattr(flock_inst, 'to_yaml', lambda: "")()
|
|
538
|
+
})
|
|
520
539
|
|
|
521
540
|
return templates.TemplateResponse(
|
|
522
541
|
"partials/_chat_messages.html",
|
|
523
542
|
{"request": request, "history": history, "now": datetime.now}
|
|
524
543
|
)
|
|
544
|
+
|
|
545
|
+
# ---------------- Feedback endpoints ----------------
|
|
546
|
+
@router.post("/chat/htmx/feedback", response_class=HTMLResponse, include_in_schema=False)
|
|
547
|
+
async def chat_feedback(request: Request,
|
|
548
|
+
reason: str = Form(...),
|
|
549
|
+
expected_response: str | None = Form(None),
|
|
550
|
+
actual_response: str | None = Form(None),
|
|
551
|
+
flock_definition: str | None = Form(None),
|
|
552
|
+
agent_name: str | None = Form(None),
|
|
553
|
+
store: SharedLinkStoreInterface = Depends(get_shared_link_store)):
|
|
554
|
+
from uuid import uuid4
|
|
555
|
+
rec = FeedbackRecord(
|
|
556
|
+
feedback_id=uuid4().hex,
|
|
557
|
+
share_id=None,
|
|
558
|
+
context_type="chat",
|
|
559
|
+
reason=reason,
|
|
560
|
+
expected_response=expected_response,
|
|
561
|
+
actual_response=actual_response,
|
|
562
|
+
flock_definition=flock_definition,
|
|
563
|
+
agent_name=agent_name,
|
|
564
|
+
)
|
|
565
|
+
await store.save_feedback(rec)
|
|
566
|
+
toast_event = {
|
|
567
|
+
"showGlobalToast": {
|
|
568
|
+
"message": "Feedback received! Thanks",
|
|
569
|
+
"type": "success"
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
headers = {"HX-Trigger": json.dumps(toast_event)}
|
|
573
|
+
return Response(status_code=204, headers=headers)
|
|
574
|
+
|
|
575
|
+
|
|
576
|
+
@router.post("/chat/htmx/feedback-shared", response_class=HTMLResponse, include_in_schema=False)
|
|
577
|
+
async def chat_feedback_shared(request: Request,
|
|
578
|
+
share_id: str = Form(...),
|
|
579
|
+
reason: str = Form(...),
|
|
580
|
+
expected_response: str | None = Form(None),
|
|
581
|
+
actual_response: str | None = Form(None),
|
|
582
|
+
flock_definition: str | None = Form(None),
|
|
583
|
+
agent_name: str | None = Form(None),
|
|
584
|
+
store: SharedLinkStoreInterface = Depends(get_shared_link_store)):
|
|
585
|
+
from uuid import uuid4
|
|
586
|
+
rec = FeedbackRecord(
|
|
587
|
+
feedback_id=uuid4().hex,
|
|
588
|
+
share_id=share_id,
|
|
589
|
+
context_type="chat",
|
|
590
|
+
reason=reason,
|
|
591
|
+
expected_response=expected_response,
|
|
592
|
+
actual_response=actual_response,
|
|
593
|
+
flock_definition=flock_definition,
|
|
594
|
+
agent_name=agent_name,
|
|
595
|
+
)
|
|
596
|
+
await store.save_feedback(rec)
|
|
597
|
+
toast_event = {
|
|
598
|
+
"showGlobalToast": {
|
|
599
|
+
"message": "Feedback received! Thanks",
|
|
600
|
+
"type": "success"
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
headers = {"HX-Trigger": json.dumps(toast_event)}
|
|
604
|
+
return Response(status_code=204, headers=headers)
|
|
@@ -41,3 +41,41 @@ class SharedLinkConfig(BaseModel):
|
|
|
41
41
|
]
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
|
+
|
|
45
|
+
# -----------------------------------------------------------
|
|
46
|
+
# Feedback model (user ratings / corrections)
|
|
47
|
+
# -----------------------------------------------------------
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class FeedbackRecord(BaseModel):
|
|
51
|
+
"""A user-submitted piece of feedback for an agent run or chat turn."""
|
|
52
|
+
|
|
53
|
+
feedback_id: str = Field(..., description="Unique identifier for this feedback entry.")
|
|
54
|
+
share_id: str | None = Field(None, description="If the feedback refers to a shared link, its ID; otherwise None.")
|
|
55
|
+
context_type: str = Field(
|
|
56
|
+
default="agent_run",
|
|
57
|
+
description="Where the feedback originates (agent_run | chat | other)",
|
|
58
|
+
)
|
|
59
|
+
reason: str = Field(..., description="User-supplied reason / comment.")
|
|
60
|
+
expected_response: str | None = Field(
|
|
61
|
+
None,
|
|
62
|
+
description="Desired or corrected response in JSON or plain text.",
|
|
63
|
+
)
|
|
64
|
+
actual_response: str | None = Field(
|
|
65
|
+
None,
|
|
66
|
+
description="Original response shown to the user (optional, for context).",
|
|
67
|
+
)
|
|
68
|
+
created_at: datetime = Field(default_factory=datetime.utcnow)
|
|
69
|
+
# When share_id is None store explicit target identifiers
|
|
70
|
+
flock_name: str | None = Field(
|
|
71
|
+
None,
|
|
72
|
+
description="Name of the flock that produced the result when no share_id is used.",
|
|
73
|
+
)
|
|
74
|
+
agent_name: str | None = Field(
|
|
75
|
+
None,
|
|
76
|
+
description="Name of the agent or chat involved in the feedback.",
|
|
77
|
+
)
|
|
78
|
+
flock_definition: str | None = Field(
|
|
79
|
+
None,
|
|
80
|
+
description="Full YAML definition of the flock when feedback was submitted.",
|
|
81
|
+
)
|
|
@@ -5,7 +5,10 @@ from pathlib import Path
|
|
|
5
5
|
|
|
6
6
|
import aiosqlite
|
|
7
7
|
|
|
8
|
-
from flock.webapp.app.services.sharing_models import
|
|
8
|
+
from flock.webapp.app.services.sharing_models import (
|
|
9
|
+
FeedbackRecord,
|
|
10
|
+
SharedLinkConfig,
|
|
11
|
+
)
|
|
9
12
|
|
|
10
13
|
# Get a logger instance
|
|
11
14
|
logger = logging.getLogger(__name__)
|
|
@@ -33,6 +36,12 @@ class SharedLinkStoreInterface(ABC):
|
|
|
33
36
|
"""Deletes a shared link configuration by its ID. Returns True if deleted, False otherwise."""
|
|
34
37
|
pass
|
|
35
38
|
|
|
39
|
+
# Feedback
|
|
40
|
+
@abstractmethod
|
|
41
|
+
async def save_feedback(self, record: FeedbackRecord):
|
|
42
|
+
"""Persist a feedback record."""
|
|
43
|
+
pass
|
|
44
|
+
|
|
36
45
|
class SQLiteSharedLinkStore(SharedLinkStoreInterface):
|
|
37
46
|
"""SQLite implementation for storing and retrieving shared link configurations."""
|
|
38
47
|
|
|
@@ -76,6 +85,25 @@ class SQLiteSharedLinkStore(SharedLinkStoreInterface):
|
|
|
76
85
|
else:
|
|
77
86
|
raise # Re-raise if it's a different operational error
|
|
78
87
|
|
|
88
|
+
# Feedback table
|
|
89
|
+
await db.execute(
|
|
90
|
+
"""
|
|
91
|
+
CREATE TABLE IF NOT EXISTS feedback (
|
|
92
|
+
feedback_id TEXT PRIMARY KEY,
|
|
93
|
+
share_id TEXT,
|
|
94
|
+
context_type TEXT NOT NULL,
|
|
95
|
+
reason TEXT NOT NULL,
|
|
96
|
+
expected_response TEXT,
|
|
97
|
+
actual_response TEXT,
|
|
98
|
+
flock_name TEXT,
|
|
99
|
+
agent_name TEXT,
|
|
100
|
+
flock_definition TEXT,
|
|
101
|
+
created_at TEXT NOT NULL,
|
|
102
|
+
FOREIGN KEY(share_id) REFERENCES shared_links(share_id)
|
|
103
|
+
)
|
|
104
|
+
"""
|
|
105
|
+
)
|
|
106
|
+
|
|
79
107
|
await db.commit()
|
|
80
108
|
logger.info(f"Database initialized and shared_links table schema ensured at {self.db_path}")
|
|
81
109
|
except sqlite3.Error as e:
|
|
@@ -154,3 +182,34 @@ class SQLiteSharedLinkStore(SharedLinkStoreInterface):
|
|
|
154
182
|
except sqlite3.Error as e:
|
|
155
183
|
logger.error(f"SQLite error deleting config for ID {share_id}: {e}", exc_info=True)
|
|
156
184
|
return False # Or raise
|
|
185
|
+
|
|
186
|
+
# ----------------------- Feedback methods -----------------------
|
|
187
|
+
|
|
188
|
+
async def save_feedback(self, record: FeedbackRecord) -> FeedbackRecord:
|
|
189
|
+
"""Persist a feedback record to SQLite."""
|
|
190
|
+
try:
|
|
191
|
+
async with aiosqlite.connect(self.db_path) as db:
|
|
192
|
+
await db.execute(
|
|
193
|
+
"""INSERT INTO feedback (
|
|
194
|
+
feedback_id, share_id, context_type, reason,
|
|
195
|
+
expected_response, actual_response, flock_name, agent_name, flock_definition, created_at
|
|
196
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)""",
|
|
197
|
+
(
|
|
198
|
+
record.feedback_id,
|
|
199
|
+
record.share_id,
|
|
200
|
+
record.context_type,
|
|
201
|
+
record.reason,
|
|
202
|
+
record.expected_response,
|
|
203
|
+
record.actual_response,
|
|
204
|
+
record.flock_name,
|
|
205
|
+
record.agent_name,
|
|
206
|
+
record.flock_definition,
|
|
207
|
+
record.created_at.isoformat(),
|
|
208
|
+
),
|
|
209
|
+
)
|
|
210
|
+
await db.commit()
|
|
211
|
+
logger.info(f"Saved feedback {record.feedback_id} (share={record.share_id})")
|
|
212
|
+
return record
|
|
213
|
+
except sqlite3.Error as e:
|
|
214
|
+
logger.error(f"SQLite error saving feedback {record.feedback_id}: {e}", exc_info=True)
|
|
215
|
+
raise
|
flock/webapp/static/css/chat.css
CHANGED
|
@@ -5,9 +5,55 @@
|
|
|
5
5
|
<span class="chat-timestamp">{{ entry.timestamp|default(now().strftime('%H:%M')) }}</span>
|
|
6
6
|
</div>
|
|
7
7
|
{% else %}
|
|
8
|
-
<div class="bubble bot">
|
|
9
|
-
|
|
10
|
-
<
|
|
8
|
+
<div class="bubble bot" x-data="{showForm:false}">
|
|
9
|
+
<!-- Bubble content (visible when feedback form hidden) -->
|
|
10
|
+
<div x-show="!showForm">
|
|
11
|
+
<div>
|
|
12
|
+
{{ entry.text | safe }}
|
|
13
|
+
<span class="chat-timestamp">
|
|
14
|
+
{{ entry.timestamp|default(now().strftime('%H:%M')) }}{% if entry.agent %} - {{ entry.agent }}{% endif %}{% if entry.duration_ms is defined %} - {{ entry.duration_ms }}ms - {% endif %}
|
|
15
|
+
<!-- hidden meta form (used by thumbs links) -->
|
|
16
|
+
<form class="feedback-meta" style="display:none">
|
|
17
|
+
{% if share_id %}<input type="hidden" name="share_id" value="{{ share_id }}">{% endif %}
|
|
18
|
+
<input type="hidden" name="flock_definition" value="{{ entry.flock_yaml | replace('"', '"') }}">
|
|
19
|
+
<input type="hidden" name="agent_name" value="{{ entry.agent }}">
|
|
20
|
+
<input type="hidden" name="actual_response" value='{{ entry.raw_json | replace("'", "'") }}'>
|
|
21
|
+
<input type="hidden" name="reason" value="positive">
|
|
22
|
+
</form>
|
|
23
|
+
|
|
24
|
+
<a href="#"
|
|
25
|
+
hx-post="{% if share_id %}/chat/htmx/feedback-shared{% else %}/chat/htmx/feedback{% endif %}"
|
|
26
|
+
hx-include="closest .feedback-meta"
|
|
27
|
+
hx-target="closest .bubble"
|
|
28
|
+
hx-swap="innerHTML"
|
|
29
|
+
title="Looks good!" class="feedback-link">👍</a>
|
|
30
|
+
-
|
|
31
|
+
<a href="#" @click.prevent="showForm=true" title="Submit detailed feedback" class="feedback-link">👎</a>
|
|
32
|
+
</span>
|
|
33
|
+
</div>
|
|
34
|
+
</div>
|
|
35
|
+
|
|
36
|
+
<!-- Feedback form (initially hidden, toggled by 👎 link) -->
|
|
37
|
+
<div x-show="showForm" style="width:800px;">
|
|
38
|
+
<form
|
|
39
|
+
hx-post="{% if share_id %}/chat/htmx/feedback-shared{% else %}/chat/htmx/feedback{% endif %}"
|
|
40
|
+
hx-swap="outerHTML"
|
|
41
|
+
x-on:htmx:afterRequest="showForm=false"
|
|
42
|
+
style="display:block; width:800px;">
|
|
43
|
+
{% if share_id %}<input type="hidden" name="share_id" value="{{ share_id }}">{% endif %}
|
|
44
|
+
<input type="hidden" name="flock_definition" value='{{ entry.flock_yaml | tojson | safe }}'>
|
|
45
|
+
<input type="hidden" name="agent_name" value='{{ entry.agent | tojson | safe }}'>
|
|
46
|
+
<input type="hidden" name="actual_response" value='{{ entry.raw_json | tojson | safe }}'>
|
|
47
|
+
<label>Reason</label>
|
|
48
|
+
<textarea name="reason" required style="min-height:5rem;width:100%; white-space:pre-wrap;"></textarea>
|
|
49
|
+
<label>Expected / Correct Response</label>
|
|
50
|
+
<textarea name="expected_response" style="min-height:12rem;width:100%; white-space:pre-wrap;font-family:monospace;">{{ entry.raw_json }}</textarea>
|
|
51
|
+
<div style="margin-top:0.4rem; display:flex; gap:0.5rem;">
|
|
52
|
+
<button type="submit" class="secondary">Send</button>
|
|
53
|
+
<button type="button" class="outline" @click="showForm=false">Back...</button>
|
|
54
|
+
</div>
|
|
55
|
+
</form>
|
|
56
|
+
</div>
|
|
11
57
|
</div>
|
|
12
58
|
{% endif %}
|
|
13
|
-
{% endfor %}
|
|
59
|
+
{% endfor %}
|
|
@@ -6,6 +6,22 @@
|
|
|
6
6
|
<div style="text-align: right;">
|
|
7
7
|
<button role="button" class="outline contrast" @click="viewMode = 'structured'" :aria-pressed="viewMode === 'structured'">Structured</button>
|
|
8
8
|
<button role="button" class="outline contrast" @click="viewMode = 'json'" :aria-pressed="viewMode === 'json'">Raw JSON</button>
|
|
9
|
+
|
|
10
|
+
<div style="display:inline-block;margin-left:0.5rem;">
|
|
11
|
+
<!-- Quick thumbs-up feedback (inline form so we have the identifiers) -->
|
|
12
|
+
<form hx-post="{{ feedback_endpoint }}" hx-target="#results-display-content" hx-swap="innerHTML" style="display:inline-block;vertical-align:middle;margin:0;" hx-indicator="#feedback-loading-indicator">
|
|
13
|
+
{% if share_id %}<input type="hidden" name="share_id" value="{{ share_id }}">{% endif %}
|
|
14
|
+
<input type="hidden" name="flock_name" value="{{ flock_name }}">
|
|
15
|
+
<input type="hidden" name="agent_name" value="{{ agent_name }}">
|
|
16
|
+
<input type="hidden" name="flock_definition" value='{{ flock_definition | replace("'", "'") }}'>
|
|
17
|
+
<input type="hidden" name="actual_response" value='{{ result_raw_json | replace("'", "'") }}'>
|
|
18
|
+
<input type="hidden" name="reason" value="positive">
|
|
19
|
+
<button type="submit" role="button" class="outline contrast" title="Looks good!" style="padding:0.3rem 0.5rem;line-height:1;vertical-align:middle;margin:0;"><i class="fa fa-thumbs-up"></i></button>
|
|
20
|
+
</form>
|
|
21
|
+
|
|
22
|
+
<!-- Thumbs-down toggles detailed feedback form -->
|
|
23
|
+
<button role="button" class="outline contrast" @click="viewMode = 'feedback'" :aria-pressed="viewMode === 'feedback'" title="Something's wrong" style="padding:0.3rem 0.5rem;line-height:1;vertical-align:middle;margin:0;"><i class="fa fa-thumbs-down"></i></button>
|
|
24
|
+
</div>
|
|
9
25
|
</div>
|
|
10
26
|
</header>
|
|
11
27
|
|
|
@@ -36,4 +52,27 @@
|
|
|
36
52
|
<p>No results to display yet.</p>
|
|
37
53
|
{% endif %}
|
|
38
54
|
</div>
|
|
55
|
+
|
|
56
|
+
<!-- ---------------- Feedback form ---------------- -->
|
|
57
|
+
<div x-show="viewMode === 'feedback'" style="margin-top: 1rem;">
|
|
58
|
+
<form hx-post="{{ feedback_endpoint }}" hx-target="#results-display-content" hx-swap="innerHTML" hx-indicator="#feedback-loading-indicator">
|
|
59
|
+
{# Hidden identifiers #}
|
|
60
|
+
{% if share_id %}
|
|
61
|
+
<input type="hidden" name="share_id" value="{{ share_id }}">
|
|
62
|
+
{% endif %}
|
|
63
|
+
<input type="hidden" name="flock_name" value="{{ flock_name }}">
|
|
64
|
+
<input type="hidden" name="agent_name" value="{{ agent_name }}">
|
|
65
|
+
<input type="hidden" name="flock_definition" value='{{ flock_definition | replace("'", "'") }}'>
|
|
66
|
+
<input type="hidden" name="actual_response" value='{{ result_raw_json | replace("'", "'") }}'>
|
|
67
|
+
|
|
68
|
+
<label for="feedback_reason">Reason / Comment</label>
|
|
69
|
+
<textarea id="feedback_reason" name="reason" placeholder="Why isn't the answer good?" required style="min-height:6rem;"></textarea>
|
|
70
|
+
|
|
71
|
+
<label for="expected_response" style="margin-top:0.5rem;">Correct / Expected Response (JSON or text)</label>
|
|
72
|
+
<textarea id="expected_response" name="expected_response" style="white-space: pre; font-family: monospace; min-height:10rem;">{{ result_raw_json }}</textarea>
|
|
73
|
+
|
|
74
|
+
<button type="submit" class="secondary" style="margin-top:0.5rem;">Send Feedback</button>
|
|
75
|
+
<span id="feedback-loading-indicator" class="htmx-indicator"><progress indeterminate></progress> Sending…</span>
|
|
76
|
+
</form>
|
|
77
|
+
</div>
|
|
39
78
|
</article>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: flock-core
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.2
|
|
4
4
|
Summary: Declarative LLM Orchestration at Scale
|
|
5
5
|
Author-email: Andre Ratzenberger <andre.ratzenberger@whiteduck.de>
|
|
6
6
|
License-File: LICENSE
|
|
@@ -21,7 +21,7 @@ Requires-Dist: litellm==1.69.3
|
|
|
21
21
|
Requires-Dist: loguru>=0.7.3
|
|
22
22
|
Requires-Dist: markdown2>=2.5.3
|
|
23
23
|
Requires-Dist: matplotlib>=3.10.0
|
|
24
|
-
Requires-Dist: mem0ai[graph]>=0.1.
|
|
24
|
+
Requires-Dist: mem0ai[graph]>=0.1.101
|
|
25
25
|
Requires-Dist: msgpack>=1.1.0
|
|
26
26
|
Requires-Dist: notion-client>=2.3.0
|
|
27
27
|
Requires-Dist: openai==1.75.0
|
|
@@ -50,6 +50,8 @@ Requires-Dist: tiktoken>=0.8.0
|
|
|
50
50
|
Requires-Dist: toml>=0.10.2
|
|
51
51
|
Requires-Dist: tqdm>=4.67.1
|
|
52
52
|
Requires-Dist: uvicorn>=0.34.0
|
|
53
|
+
Requires-Dist: wd-di>=0.2.14
|
|
54
|
+
Requires-Dist: zep-python>=2.0.2
|
|
53
55
|
Provides-Extra: all-tools
|
|
54
56
|
Requires-Dist: azure-identity>=1.23.0; extra == 'all-tools'
|
|
55
57
|
Requires-Dist: azure-search-documents>=11.5.2; extra == 'all-tools'
|
|
@@ -87,11 +89,7 @@ Description-Content-Type: text/markdown
|
|
|
87
89
|
<a href="https://bsky.app/profile/whiteduck-gmbh.bsky.social" target="_blank"><img alt="Bluesky" src="https://img.shields.io/badge/bluesky-Follow-blue?style=for-the-badge&logo=bluesky&logoColor=%23fff&color=%23333&labelColor=%230285FF&label=whiteduck-gmbh"></a>
|
|
88
90
|
</p>
|
|
89
91
|
|
|
90
|
-
🐤 Flock 0.4.0 currently in beta - use `pip install flock-core==0.4.0b5` 🐤
|
|
91
92
|
|
|
92
|
-
🐤 `pip install flock-core` will install the latest non-beta version 🐤
|
|
93
|
-
|
|
94
|
-
🐤 Expected Release for 0.4.0 `Magpie`: End of April 2025 🐤
|
|
95
93
|
|
|
96
94
|
---
|
|
97
95
|
|
|
@@ -296,7 +294,7 @@ Flock makes this easy with:
|
|
|
296
294
|
* **Declarative Configuration:** Define Temporal timeouts, retry policies, and task queues directly within your `Flock` and `FlockAgent` configurations (YAML or Python).
|
|
297
295
|
* **Correct Patterns:** Uses Temporal's recommended granular activity execution for better control and visibility.
|
|
298
296
|
* **Clear Worker Separation:** Provides guidance and flags for running dedicated Temporal workers, separating development convenience from production best practices.
|
|
299
|
-
|
|
297
|
+
|
|
300
298
|
Visit the [Temporal Documentation](https://learn.temporal.io/python/workflows/) for more information on how to use Temporal.
|
|
301
299
|
|
|
302
300
|
Or check out the [Flock Showcase](https://github.com/whiteducksoftware/flock-showcase) for a complete example of a Flock that uses Temporal or our [docs](https://whiteducksoftware.github.io/flock/guides/temporal-configuration/) for more information.
|