ai_co_discuss 0.3.38 → 0.3.39
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.
- package/.agents/skills/discuss-host/references/free.md +1 -1
- package/.agents/skills/discuss-participant/SKILL.md +2 -0
- package/.agents/skills/discuss-participant/references/free.md +1 -1
- package/backend/free_room.py +79 -5
- package/backend/identity.py +40 -31
- package/backend/schema.sql +166 -0
- package/backend/server.py +2553 -2458
- package/docs/runner.md +1 -1
- package/package.json +1 -1
- package/runner/adapters/antigravity_cli.mjs +5 -1
- package/runner/adapters/cli.mjs +2 -1
- package/runner/discuss.py +21 -4
- package/runner/free_runner.mjs +13 -5
- package/web/app.js +15 -4
- package/web/markdown.js +2 -2
- package/web/modern.css +1 -1
- package/web/modern.js +2825 -2403
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
|
|
17
17
|
## 派活
|
|
18
18
|
|
|
19
|
-
- 需要他人时在回答中加 `--to
|
|
19
|
+
- 需要他人时在回答中加 `--to 显示名`(可重复,不能点名自己),写明各自负责的文件或模块;不需要他人时不加,本次即结束。
|
|
20
20
|
- 只点名一位成员时,它的回答直接面向用户;还要按结果安排下一步(如再交评审)时加 `--handoff`,它做完你会再被唤醒。点名多位时,全部结束后总会回到你汇总。
|
|
21
21
|
- 需要预先指定实现后的只读评审时,先读 `review roster ROOM`,再在派实现的 `message post` 中带 `--next-review NAME --review-scope 范围 --review-roster REVISION`;评审者不能是本批实现者。授权与实现任务同时保存,自动要求该批交回主持人。候选目前限程序启动的 Codex CLI;没有合格成员时读取结果给出原因。
|
|
22
22
|
- 收到 `review_handoffs` 时,先用 `review ready ROOM --batch ID` 读取完整委派、交付和报告,确认可交既定评审后用 `review advance ROOM --batch ID --revision REV --submission-id UUID --as 本人` 推进。只处理该批交接,其他请求继续完成;状态变化须重读,不能替换评审者或扩大权限。能力失效、额度不足、交付不完整等原因保留在读取结果和任务中。实际投递前本机复核只读权限与能力版本,失败撤销该次评审并交回主持人。
|
|
@@ -37,6 +37,8 @@ description: "AI CoDiscuss 的通用参与技能,所有参与者(包括主
|
|
|
37
37
|
|
|
38
38
|
每次 shell 调用都是一次模型往返,手动会话里还可能要用户逐条确认,所以互不依赖的只读命令放进同一条 shell 命令依次执行。正文想好后,先用当前软件的文件写入工具把正文(和需要的摘要)写成草稿文件,再用一条只含 `codiscuss` 的命令以 `--body-file`(`--summary-file`)提交;失败重试仍用这份草稿。不要用 heredoc、`echo` 重定向或命令行字面量传长文本,也不要在命令里调用函数生成编号(如 `[guid]::NewGuid()`、`$(uuidgen)`):自动运行时这类组合命令会被权限检查拒绝,文本中的引号(含中文弯引号)还会截断参数。其他写入命令需要编号时直接写一个新的 UUID 字面值。不同的网站写入各自单独执行并核对结果。
|
|
39
39
|
|
|
40
|
+
称呼和点名成员一律用显示名:`room view` 中 `members[].label`(如 `Gemini`)就是它在房间里的名字,正文 `@`、`--to`、`--next-review`、`--expert` 都写它。`name` 是成员 ID,与 `descriptions` 同属成员的完整信息,需要核对时再看,不写进正文;旧消息、`author` 等字段里出现的 ID 指的是同一位成员。
|
|
41
|
+
|
|
40
42
|
## 阅读
|
|
41
43
|
|
|
42
44
|
背景不足读 `room brief`,需要接续判断读 `state view`,核对具体论据读 `message view ROOM ID`,查找材料才用 `message list`。按争点阅读相关原文,不用摘要代替需要复核的论证,也不无目的拉取全部历史。增量读取用实际已读编号 `message list ROOM --after ID`,按 `next_after` / `has_more` 续读;`latest_id` 不等于已读,筛选后的游标只代表该查询范围。阶段和安排以最新服务端状态为准。
|
package/backend/free_room.py
CHANGED
|
@@ -15,7 +15,7 @@ import re
|
|
|
15
15
|
import time
|
|
16
16
|
import uuid
|
|
17
17
|
|
|
18
|
-
from .identity import MAX_ROOM_AGENTS, is_ai
|
|
18
|
+
from .identity import MAX_ROOM_AGENTS, default_label, is_ai
|
|
19
19
|
from .message_queue import pause as pause_queue, queue_view
|
|
20
20
|
from .runtime import (LEASE_SECONDS, MAX_EXECUTION_SEGMENTS, begin_write, enforce_session_limits,
|
|
21
21
|
require_owner, save_segments, token_hash)
|
|
@@ -43,6 +43,13 @@ RECENT_EXECUTIONS = 100
|
|
|
43
43
|
# The timeline page reads this many recent executions of each kind; with `after` (?3) only those running or ended since.
|
|
44
44
|
# Parameters: ?1 room, ?2 limit, ?3 after (0 reads all). Shared verbatim with the Worker.
|
|
45
45
|
TIMELINE_EXECUTIONS = 100
|
|
46
|
+
# The event log page reads at most this many room events per call, newest first when paging back.
|
|
47
|
+
ROOM_EVENT_PAGE = 500
|
|
48
|
+
# The message a request's card sits under, for member_requests aliased `r`. A handoff request belongs to the dispatch
|
|
49
|
+
# message (`message_id`, which batch logic relies on) but happens because the batch's last answer arrived, so its card
|
|
50
|
+
# and answer sit under that answer; later messages (the user asking something meanwhile) then stay above it.
|
|
51
|
+
ANCHOR_SQL = """CASE WHEN r.purpose='handoff' THEN COALESCE((SELECT MAX(a.answer_id) FROM member_requests a
|
|
52
|
+
WHERE a.room_id=r.room_id AND a.batch_id=r.message_id AND a.purpose<>'handoff'), r.message_id) ELSE r.message_id END"""
|
|
46
53
|
# Rounds used and allowed in the room's recent chains, for "第 2/3 轮"; parameters: the room's limit, the room.
|
|
47
54
|
CHAIN_PROGRESS_SQL = """SELECT b.chain_id,COUNT(*) AS used,? + COALESCE((SELECT h.extra_rounds FROM free_chain_holds h
|
|
48
55
|
WHERE h.room_id=b.room_id AND h.chain_id=b.chain_id),0) AS allowed FROM free_batches b WHERE b.room_id=?
|
|
@@ -526,6 +533,38 @@ def member_labels(connection, room_id):
|
|
|
526
533
|
"SELECT name,label FROM member_labels WHERE room_id=? ORDER BY name", (room_id,))}
|
|
527
534
|
|
|
528
535
|
|
|
536
|
+
def member_display_names(connection, room_id):
|
|
537
|
+
"""What each present member is called in text: the owner's label, else its platform nickname, else its ID."""
|
|
538
|
+
labels = member_labels(connection, room_id)
|
|
539
|
+
return {row["name"]: labels.get(row["name"]) or default_label(row["name"]) for row in connection.execute(
|
|
540
|
+
"SELECT name FROM room_members WHERE room_id=? AND status<>'removed' ORDER BY id", (room_id,))}
|
|
541
|
+
|
|
542
|
+
|
|
543
|
+
def member_handles(connection, room_id):
|
|
544
|
+
"""Every way to name a present member, mapped to its ID: the ID, and its display name unless another member shares it."""
|
|
545
|
+
shown = member_display_names(connection, room_id)
|
|
546
|
+
handles = {name: name for name in shown}
|
|
547
|
+
taken = list(shown.values())
|
|
548
|
+
for name, label in shown.items():
|
|
549
|
+
if label not in handles and taken.count(label) == 1:
|
|
550
|
+
handles[label] = name
|
|
551
|
+
return handles
|
|
552
|
+
|
|
553
|
+
|
|
554
|
+
def resolve_member_fields(connection, room_id, payload):
|
|
555
|
+
"""Turn display names in a write's member fields into IDs, so members are named as they are seen; IDs still work."""
|
|
556
|
+
handles = member_handles(connection, room_id)
|
|
557
|
+
resolve = lambda value: handles.get(value.strip(), value) if isinstance(value, str) else value
|
|
558
|
+
if isinstance(payload.get("to"), list):
|
|
559
|
+
payload["to"] = [resolve(item) for item in payload["to"]]
|
|
560
|
+
for key in ("next_review", "expert"):
|
|
561
|
+
if key in payload:
|
|
562
|
+
payload[key] = resolve(payload[key])
|
|
563
|
+
if isinstance(payload.get("turns"), list):
|
|
564
|
+
payload["turns"] = [{**item, "expert": resolve(item.get("expert"))} if isinstance(item, dict) else item for item in payload["turns"]]
|
|
565
|
+
return payload
|
|
566
|
+
|
|
567
|
+
|
|
529
568
|
def label_members(connection, room_id, token, payload):
|
|
530
569
|
"""Owner sets members' display labels by name; an empty text removes that member's label."""
|
|
531
570
|
require_owner(connection, room_id, token)
|
|
@@ -593,12 +632,43 @@ def execution_timeline(connection, room_id, after=0):
|
|
|
593
632
|
"segment_limit": MAX_EXECUTION_SEGMENTS}
|
|
594
633
|
|
|
595
634
|
|
|
635
|
+
def room_event_log(connection, room_id, token, after=0, before=0):
|
|
636
|
+
"""Read the owner's append-only room event log written by the schema triggers.
|
|
637
|
+
|
|
638
|
+
Args:
|
|
639
|
+
after: return events with a larger id (live follow), oldest first.
|
|
640
|
+
before: with no `after`, return the page of events just below this id (0 = the newest page), oldest first.
|
|
641
|
+
|
|
642
|
+
Returns:
|
|
643
|
+
`events` (id, at in epoch ms, kind, data) ordered by `at` then id, `members` id → name for resolving
|
|
644
|
+
`member_id`/`host_id`, `first_id`/`last_id` as paging cursors, and `more` when older events remain.
|
|
645
|
+
A write request (`api.*`) is stored after it finishes, so its id follows the changes it caused; its `at` is
|
|
646
|
+
when it arrived, and ordering by `at` puts the input before its effects.
|
|
647
|
+
"""
|
|
648
|
+
require_owner(connection, room_id, token)
|
|
649
|
+
after, before = max(0, int(after)), max(0, int(before))
|
|
650
|
+
if after:
|
|
651
|
+
rows = connection.execute("SELECT id,at,kind,data FROM room_events WHERE room_id=? AND id>? ORDER BY id LIMIT ?",
|
|
652
|
+
(room_id, after, ROOM_EVENT_PAGE)).fetchall()
|
|
653
|
+
else:
|
|
654
|
+
rows = connection.execute("""SELECT id,at,kind,data FROM room_events WHERE room_id=? AND (?=0 OR id<?)
|
|
655
|
+
ORDER BY id DESC LIMIT ?""", (room_id, before, before, ROOM_EVENT_PAGE)).fetchall()
|
|
656
|
+
first_id = min((row["id"] for row in rows), default=0)
|
|
657
|
+
more = bool(rows) and not after and connection.execute(
|
|
658
|
+
"SELECT 1 FROM room_events WHERE room_id=? AND id<? LIMIT 1", (room_id, first_id)).fetchone() is not None
|
|
659
|
+
members = {str(row["id"]): row["name"] for row in connection.execute("SELECT id,name FROM room_members WHERE room_id=?", (room_id,))}
|
|
660
|
+
events = sorted(({**dict(row), "data": json.loads(row["data"])} for row in rows), key=lambda event: (event["at"], event["id"]))
|
|
661
|
+
return {"events": events, "members": members, "more": more, "first_id": first_id,
|
|
662
|
+
"last_id": max((row["id"] for row in rows), default=after)}
|
|
663
|
+
|
|
664
|
+
|
|
596
665
|
def recent_executions(connection, room_id):
|
|
597
666
|
"""Return bounded public reports, including requests no longer in the recent request list."""
|
|
598
667
|
rows = connection.execute(f"""SELECT e.*,m.name AS member,
|
|
599
668
|
(SELECT json_group_array(id) FROM member_requests WHERE execution_id=e.id) AS request_ids,
|
|
600
669
|
(SELECT MAX(answer_id) FROM member_requests WHERE execution_id=e.id) AS answer_id,
|
|
601
670
|
(SELECT MIN(message_id) FROM member_requests WHERE execution_id=e.id) AS request_message_id,
|
|
671
|
+
(SELECT MIN({ANCHOR_SQL}) FROM member_requests r WHERE r.execution_id=e.id) AS anchor_message_id,
|
|
602
672
|
(SELECT COUNT(*) FROM execution_notes WHERE execution_id=e.id) AS note_count,
|
|
603
673
|
(SELECT denials FROM execution_denials WHERE execution_id=e.id) AS denials,{CAPABILITY_COLUMNS},
|
|
604
674
|
(SELECT json_object('created_at',created_at) FROM late_answers WHERE execution_id=e.id) AS late_answer
|
|
@@ -610,7 +680,8 @@ def recent_executions(connection, room_id):
|
|
|
610
680
|
requests.append({**dict(request), **session_request_source(connection, request["id"], request["message_id"])})
|
|
611
681
|
executions.append({**public_execution(row), "member": row["member"], "cwd": row["cwd"], "changes": json.loads(row["changes"] or "[]"),
|
|
612
682
|
"changes_recorded": bool(row["changes"]), "request_ids": json.loads(row["request_ids"]),
|
|
613
|
-
"answer_id": row["answer_id"], "request_message_id": row["request_message_id"],
|
|
683
|
+
"answer_id": row["answer_id"], "request_message_id": row["request_message_id"],
|
|
684
|
+
"anchor_message_id": row["anchor_message_id"], "requests": requests,
|
|
614
685
|
"notes": row["note_count"], "denials": json.loads(row["denials"] or "[]"),
|
|
615
686
|
"capabilities": reported_capabilities(row), "stop_result": row["stop_result"] or "",
|
|
616
687
|
"late_answer": json.loads(row["late_answer"]) if row["late_answer"] else None,
|
|
@@ -898,9 +969,10 @@ def save_suggestions(connection, room_id, message_id, member, payload):
|
|
|
898
969
|
active = active_members(connection, room_id)
|
|
899
970
|
targets = set(named_members(active, payload["to"] if payload.get("to") is not None else [], exclude=member["name"]))
|
|
900
971
|
prose = mention_prose(str(payload.get("text", "")))
|
|
901
|
-
for
|
|
902
|
-
if name != member["name"] and re.search(
|
|
903
|
-
|
|
972
|
+
for handle, name in member_handles(connection, room_id).items():
|
|
973
|
+
if name in active and name != member["name"] and re.search(
|
|
974
|
+
r"(^|[\s((,,。;;::])@" + re.escape(handle) + r"(?![A-Za-z0-9_\-\u4e00-\u9fff])", prose):
|
|
975
|
+
targets.add(active[name]["id"])
|
|
904
976
|
for target_id in targets:
|
|
905
977
|
connection.execute("INSERT INTO member_suggestions (message_id,member_id) VALUES (?,?)", (message_id, target_id))
|
|
906
978
|
|
|
@@ -1286,6 +1358,7 @@ def inbox(connection, room_id, token):
|
|
|
1286
1358
|
release_recommendations(connection, room_id)
|
|
1287
1359
|
archived = connection.execute("SELECT archived FROM room_directory WHERE room_id=?", (room_id,)).fetchone()[0]
|
|
1288
1360
|
members, observers = [], []
|
|
1361
|
+
shown = member_display_names(connection, room_id)
|
|
1289
1362
|
# Manual members are never delivered to; the runner only reads them so smart scheduling can route to them too.
|
|
1290
1363
|
for row in connection.execute(f"SELECT * FROM room_members WHERE room_id=? AND status='active' AND {REGISTERED_MEMBER} ORDER BY id", (room_id,)):
|
|
1291
1364
|
pending = [dict(item) for item in connection.execute("""SELECT r.id,r.message_id,r.purpose,
|
|
@@ -1296,6 +1369,7 @@ def inbox(connection, room_id, token):
|
|
|
1296
1369
|
LEFT JOIN task_message_sources t ON t.session_request_id=sr.id
|
|
1297
1370
|
WHERE r.member_id=? AND r.status='pending' ORDER BY r.id""", (row["id"],))]
|
|
1298
1371
|
member_view = {key: row[key] for key in MEMBER_FIELDS}
|
|
1372
|
+
member_view["label"] = shown.get(row["name"], row["name"])
|
|
1299
1373
|
member_view["review_capability"] = review_capability(connection, room_id, row["id"], token)
|
|
1300
1374
|
member_view["held_until"] = held_until(connection, row["id"])
|
|
1301
1375
|
# The runner compares this with its adapter's effect and reports a change.
|
package/backend/identity.py
CHANGED
|
@@ -1,31 +1,40 @@
|
|
|
1
|
-
"""Participant identities: an AI platform is a type, a room participant is one named instance of it.
|
|
2
|
-
|
|
3
|
-
`Claude` and `Claude-review` are two instances of the Claude platform in the same room; each keeps its
|
|
4
|
-
own session, model and thinking effort. Platform names alone keep their historical meaning.
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
import re
|
|
8
|
-
|
|
9
|
-
USER = "用户"
|
|
10
|
-
AI_PLATFORMS = ("Codex", "Claude", "Antigravity", "DeepSeek", "Qwen", "Grok")
|
|
11
|
-
PARTICIPANTS = [USER, *AI_PLATFORMS]
|
|
12
|
-
MAX_INSTANCE_SUFFIX = 16
|
|
13
|
-
# AI instances one room may hold, across platforms.
|
|
14
|
-
MAX_ROOM_AGENTS = 12
|
|
15
|
-
INSTANCE_PATTERN = re.compile(rf"({'|'.join(AI_PLATFORMS)})(?:-[0-9A-Za-z_]{{1,{MAX_INSTANCE_SUFFIX}}})?")
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
1
|
+
"""Participant identities: an AI platform is a type, a room participant is one named instance of it.
|
|
2
|
+
|
|
3
|
+
`Claude` and `Claude-review` are two instances of the Claude platform in the same room; each keeps its
|
|
4
|
+
own session, model and thinking effort. Platform names alone keep their historical meaning.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import re
|
|
8
|
+
|
|
9
|
+
USER = "用户"
|
|
10
|
+
AI_PLATFORMS = ("Codex", "Claude", "Antigravity", "DeepSeek", "Qwen", "Grok")
|
|
11
|
+
PARTICIPANTS = [USER, *AI_PLATFORMS]
|
|
12
|
+
MAX_INSTANCE_SUFFIX = 16
|
|
13
|
+
# AI instances one room may hold, across platforms.
|
|
14
|
+
MAX_ROOM_AGENTS = 12
|
|
15
|
+
INSTANCE_PATTERN = re.compile(rf"({'|'.join(AI_PLATFORMS)})(?:-[0-9A-Za-z_]{{1,{MAX_INSTANCE_SUFFIX}}})?")
|
|
16
|
+
# The name people and AIs call a platform when it differs from its ID; web/app.js PLATFORM_IDENTITIES shows the same.
|
|
17
|
+
PLATFORM_NICKNAMES = {"Antigravity": "Gemini"}
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def is_ai(name):
|
|
21
|
+
"""Whether a name is an AI platform or a named instance of one."""
|
|
22
|
+
return isinstance(name, str) and INSTANCE_PATTERN.fullmatch(name) is not None
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def is_participant(name):
|
|
26
|
+
"""Whether a name may author, submit or be scheduled: the user or any AI instance."""
|
|
27
|
+
return name == USER or is_ai(name)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def platform_of(name):
|
|
31
|
+
"""Return the platform an AI instance belongs to, or None for the user and invalid names."""
|
|
32
|
+
match = INSTANCE_PATTERN.fullmatch(name) if isinstance(name, str) else None
|
|
33
|
+
return match.group(1) if match else None
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def default_label(name):
|
|
37
|
+
"""The name an instance goes by without an owner's label: its platform's nickname plus its own suffix (Antigravity-2 → Gemini-2)."""
|
|
38
|
+
platform = platform_of(name)
|
|
39
|
+
nickname = PLATFORM_NICKNAMES.get(platform)
|
|
40
|
+
return nickname + name[len(platform):] if nickname else name
|
package/backend/schema.sql
CHANGED
|
@@ -1328,3 +1328,169 @@ UPDATE free_chain_holds SET names=replace(replace(names,'"Gemini"','"Antigravity
|
|
|
1328
1328
|
UPDATE room_creations SET request_text=replace(replace(request_text,'"Gemini"','"Antigravity"'),'"Gemini-','"Antigravity-') WHERE request_text LIKE '%"Gemini%';
|
|
1329
1329
|
UPDATE session_start_submissions SET request_json=replace(replace(request_json,'"Gemini"','"Antigravity"'),'"Gemini-','"Antigravity-') WHERE request_json LIKE '%"Gemini%';
|
|
1330
1330
|
UPDATE scheduler_decision_inputs SET input=replace(replace(input,'"Gemini"','"Antigravity"'),'"Gemini-','"Antigravity-') WHERE input LIKE '%"Gemini%';
|
|
1331
|
+
-- Room event log: an append-only record of each room state change, written by the triggers below so every code path
|
|
1332
|
+
-- is covered and later edits cannot forget it. State tables are overwritten in place; this log keeps the order of
|
|
1333
|
+
-- what happened (which request was created under which message, why it was cancelled, which batch handed back) so the
|
|
1334
|
+
-- timeline page can list and replay it. `at` is epoch milliseconds; `data` holds ids, names resolve at read time.
|
|
1335
|
+
CREATE TABLE IF NOT EXISTS room_events (
|
|
1336
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
1337
|
+
room_id TEXT NOT NULL REFERENCES rooms(id) ON DELETE CASCADE,
|
|
1338
|
+
at INTEGER NOT NULL,
|
|
1339
|
+
kind TEXT NOT NULL,
|
|
1340
|
+
data TEXT NOT NULL DEFAULT '{}'
|
|
1341
|
+
);
|
|
1342
|
+
CREATE INDEX IF NOT EXISTS room_events_room ON room_events(room_id,id);
|
|
1343
|
+
DROP TRIGGER IF EXISTS event_message_posted;
|
|
1344
|
+
CREATE TRIGGER event_message_posted AFTER INSERT ON messages
|
|
1345
|
+
BEGIN
|
|
1346
|
+
INSERT INTO room_events (room_id,at,kind,data) VALUES (NEW.room_id,CAST((julianday('now')-2440587.5)*86400000 AS INTEGER),'message.posted',
|
|
1347
|
+
json_object('message_id',NEW.id,'author',NEW.author,'source',NEW.source,'reply_to',NEW.reply_to,'text',substr(NEW.text,1,80)));
|
|
1348
|
+
END;
|
|
1349
|
+
DROP TRIGGER IF EXISTS event_message_withdrawn;
|
|
1350
|
+
CREATE TRIGGER event_message_withdrawn AFTER INSERT ON message_withdrawals
|
|
1351
|
+
BEGIN
|
|
1352
|
+
INSERT INTO room_events (room_id,at,kind,data) SELECT room_id,CAST((julianday('now')-2440587.5)*86400000 AS INTEGER),'message.withdrawn',
|
|
1353
|
+
json_object('message_id',NEW.message_id,'kind',NEW.kind) FROM messages WHERE id=NEW.message_id;
|
|
1354
|
+
END;
|
|
1355
|
+
DROP TRIGGER IF EXISTS event_room_rewound;
|
|
1356
|
+
CREATE TRIGGER event_room_rewound AFTER INSERT ON room_rewinds
|
|
1357
|
+
BEGIN
|
|
1358
|
+
INSERT INTO room_events (room_id,at,kind,data) VALUES (NEW.room_id,CAST((julianday('now')-2440587.5)*86400000 AS INTEGER),'room.rewound',
|
|
1359
|
+
json_object('rewind_id',NEW.id,'message_id',NEW.message_id));
|
|
1360
|
+
END;
|
|
1361
|
+
DROP TRIGGER IF EXISTS event_member_joined;
|
|
1362
|
+
CREATE TRIGGER event_member_joined AFTER INSERT ON room_members
|
|
1363
|
+
BEGIN
|
|
1364
|
+
INSERT INTO room_events (room_id,at,kind,data) VALUES (NEW.room_id,CAST((julianday('now')-2440587.5)*86400000 AS INTEGER),'member.joined',
|
|
1365
|
+
json_object('member_id',NEW.id,'role',NEW.role,'status',NEW.status,'adapter',NEW.adapter));
|
|
1366
|
+
END;
|
|
1367
|
+
DROP TRIGGER IF EXISTS event_member_changed;
|
|
1368
|
+
CREATE TRIGGER event_member_changed AFTER UPDATE OF role,status ON room_members
|
|
1369
|
+
WHEN OLD.role IS NOT NEW.role OR OLD.status IS NOT NEW.status
|
|
1370
|
+
BEGIN
|
|
1371
|
+
INSERT INTO room_events (room_id,at,kind,data) VALUES (NEW.room_id,CAST((julianday('now')-2440587.5)*86400000 AS INTEGER),'member.changed',
|
|
1372
|
+
json_object('member_id',NEW.id,'role',NEW.role,'status',NEW.status,'from_role',OLD.role,'from_status',OLD.status));
|
|
1373
|
+
END;
|
|
1374
|
+
DROP TRIGGER IF EXISTS event_request_created;
|
|
1375
|
+
CREATE TRIGGER event_request_created AFTER INSERT ON member_requests
|
|
1376
|
+
BEGIN
|
|
1377
|
+
INSERT INTO room_events (room_id,at,kind,data) VALUES (NEW.room_id,CAST((julianday('now')-2440587.5)*86400000 AS INTEGER),'request.created',
|
|
1378
|
+
json_object('request_id',NEW.id,'member_id',NEW.member_id,'message_id',NEW.message_id,'purpose',NEW.purpose,
|
|
1379
|
+
'created_by',NEW.created_by,'chain_id',NEW.chain_id,'batch_id',NEW.batch_id,'status',NEW.status));
|
|
1380
|
+
END;
|
|
1381
|
+
DROP TRIGGER IF EXISTS event_request_changed;
|
|
1382
|
+
CREATE TRIGGER event_request_changed AFTER UPDATE OF status,execution_id,answer_id ON member_requests
|
|
1383
|
+
WHEN OLD.status IS NOT NEW.status OR OLD.execution_id IS NOT NEW.execution_id OR OLD.answer_id IS NOT NEW.answer_id
|
|
1384
|
+
BEGIN
|
|
1385
|
+
INSERT INTO room_events (room_id,at,kind,data) VALUES (NEW.room_id,CAST((julianday('now')-2440587.5)*86400000 AS INTEGER),'request.changed',
|
|
1386
|
+
json_object('request_id',NEW.id,'member_id',NEW.member_id,'message_id',NEW.message_id,'status',NEW.status,
|
|
1387
|
+
'from_status',OLD.status,'execution_id',NEW.execution_id,'answer_id',NEW.answer_id));
|
|
1388
|
+
END;
|
|
1389
|
+
DROP TRIGGER IF EXISTS event_request_cancel_reason;
|
|
1390
|
+
CREATE TRIGGER event_request_cancel_reason AFTER INSERT ON request_cancel_reasons
|
|
1391
|
+
BEGIN
|
|
1392
|
+
INSERT INTO room_events (room_id,at,kind,data) SELECT room_id,CAST((julianday('now')-2440587.5)*86400000 AS INTEGER),'request.cancel_reason',
|
|
1393
|
+
json_object('request_id',NEW.request_id,'member_id',member_id,'reason',NEW.reason) FROM member_requests WHERE id=NEW.request_id;
|
|
1394
|
+
END;
|
|
1395
|
+
DROP TRIGGER IF EXISTS event_execution_created;
|
|
1396
|
+
CREATE TRIGGER event_execution_created AFTER INSERT ON member_executions
|
|
1397
|
+
BEGIN
|
|
1398
|
+
INSERT INTO room_events (room_id,at,kind,data) VALUES (NEW.room_id,CAST((julianday('now')-2440587.5)*86400000 AS INTEGER),'execution.created',
|
|
1399
|
+
json_object('execution_id',NEW.id,'member_id',NEW.member_id,'status',NEW.status));
|
|
1400
|
+
END;
|
|
1401
|
+
DROP TRIGGER IF EXISTS event_execution_changed;
|
|
1402
|
+
CREATE TRIGGER event_execution_changed AFTER UPDATE OF status ON member_executions
|
|
1403
|
+
WHEN OLD.status IS NOT NEW.status
|
|
1404
|
+
BEGIN
|
|
1405
|
+
INSERT INTO room_events (room_id,at,kind,data) VALUES (NEW.room_id,CAST((julianday('now')-2440587.5)*86400000 AS INTEGER),'execution.changed',
|
|
1406
|
+
json_object('execution_id',NEW.id,'member_id',NEW.member_id,'status',NEW.status,'from_status',OLD.status,'result',substr(NEW.result,1,200)));
|
|
1407
|
+
END;
|
|
1408
|
+
DROP TRIGGER IF EXISTS event_execution_retry;
|
|
1409
|
+
CREATE TRIGGER event_execution_retry AFTER INSERT ON execution_retries
|
|
1410
|
+
BEGIN
|
|
1411
|
+
INSERT INTO room_events (room_id,at,kind,data) VALUES (NEW.room_id,CAST((julianday('now')-2440587.5)*86400000 AS INTEGER),'execution.retry',
|
|
1412
|
+
json_object('execution_id',NEW.execution_id,'attempt',NEW.attempt,'retry_at',NEW.retry_at,'reason',substr(NEW.reason,1,200),'stopped',NEW.stopped));
|
|
1413
|
+
END;
|
|
1414
|
+
DROP TRIGGER IF EXISTS event_execution_retry_changed;
|
|
1415
|
+
CREATE TRIGGER event_execution_retry_changed AFTER UPDATE ON execution_retries
|
|
1416
|
+
WHEN OLD.attempt IS NOT NEW.attempt OR OLD.stopped IS NOT NEW.stopped
|
|
1417
|
+
BEGIN
|
|
1418
|
+
INSERT INTO room_events (room_id,at,kind,data) VALUES (NEW.room_id,CAST((julianday('now')-2440587.5)*86400000 AS INTEGER),'execution.retry',
|
|
1419
|
+
json_object('execution_id',NEW.execution_id,'attempt',NEW.attempt,'retry_at',NEW.retry_at,'reason',substr(NEW.reason,1,200),'stopped',NEW.stopped));
|
|
1420
|
+
END;
|
|
1421
|
+
DROP TRIGGER IF EXISTS event_execution_late_answer;
|
|
1422
|
+
CREATE TRIGGER event_execution_late_answer AFTER INSERT ON late_answers
|
|
1423
|
+
BEGIN
|
|
1424
|
+
INSERT INTO room_events (room_id,at,kind,data) VALUES (NEW.room_id,CAST((julianday('now')-2440587.5)*86400000 AS INTEGER),'execution.late_answer',
|
|
1425
|
+
json_object('execution_id',NEW.execution_id,'text',substr(NEW.text,1,80)));
|
|
1426
|
+
END;
|
|
1427
|
+
DROP TRIGGER IF EXISTS event_batch_opened;
|
|
1428
|
+
CREATE TRIGGER event_batch_opened AFTER INSERT ON free_batches
|
|
1429
|
+
BEGIN
|
|
1430
|
+
INSERT INTO room_events (room_id,at,kind,data) VALUES (NEW.room_id,CAST((julianday('now')-2440587.5)*86400000 AS INTEGER),'batch.opened',
|
|
1431
|
+
json_object('batch_id',NEW.batch_id,'chain_id',NEW.chain_id,'host_id',NEW.host_id));
|
|
1432
|
+
END;
|
|
1433
|
+
DROP TRIGGER IF EXISTS event_batch_settled;
|
|
1434
|
+
CREATE TRIGGER event_batch_settled AFTER UPDATE OF settled ON free_batches
|
|
1435
|
+
WHEN OLD.settled IS NOT NEW.settled
|
|
1436
|
+
BEGIN
|
|
1437
|
+
INSERT INTO room_events (room_id,at,kind,data) VALUES (NEW.room_id,CAST((julianday('now')-2440587.5)*86400000 AS INTEGER),'batch.settled',
|
|
1438
|
+
json_object('batch_id',NEW.batch_id,'chain_id',NEW.chain_id,'settled',NEW.settled));
|
|
1439
|
+
END;
|
|
1440
|
+
DROP TRIGGER IF EXISTS event_batch_handoff;
|
|
1441
|
+
CREATE TRIGGER event_batch_handoff AFTER INSERT ON free_handoffs
|
|
1442
|
+
BEGIN
|
|
1443
|
+
INSERT INTO room_events (room_id,at,kind,data) VALUES (NEW.room_id,CAST((julianday('now')-2440587.5)*86400000 AS INTEGER),'batch.handoff',
|
|
1444
|
+
json_object('batch_id',NEW.batch_id));
|
|
1445
|
+
END;
|
|
1446
|
+
DROP TRIGGER IF EXISTS event_queue_added;
|
|
1447
|
+
CREATE TRIGGER event_queue_added AFTER INSERT ON free_queue
|
|
1448
|
+
BEGIN
|
|
1449
|
+
INSERT INTO room_events (room_id,at,kind,data) VALUES (NEW.room_id,CAST((julianday('now')-2440587.5)*86400000 AS INTEGER),'queue.added',
|
|
1450
|
+
json_object('queue_id',NEW.id,'message_id',NEW.message_id,'member_id',NEW.member_id));
|
|
1451
|
+
END;
|
|
1452
|
+
DROP TRIGGER IF EXISTS event_queue_removed;
|
|
1453
|
+
CREATE TRIGGER event_queue_removed AFTER DELETE ON free_queue
|
|
1454
|
+
BEGIN
|
|
1455
|
+
INSERT INTO room_events (room_id,at,kind,data) SELECT OLD.room_id,CAST((julianday('now')-2440587.5)*86400000 AS INTEGER),'queue.removed',
|
|
1456
|
+
json_object('queue_id',OLD.id,'message_id',OLD.message_id,'member_id',OLD.member_id) WHERE EXISTS (SELECT 1 FROM rooms WHERE id=OLD.room_id);
|
|
1457
|
+
END;
|
|
1458
|
+
DROP TRIGGER IF EXISTS event_chain_held;
|
|
1459
|
+
CREATE TRIGGER event_chain_held AFTER INSERT ON free_chain_holds
|
|
1460
|
+
BEGIN
|
|
1461
|
+
INSERT INTO room_events (room_id,at,kind,data) VALUES (NEW.room_id,CAST((julianday('now')-2440587.5)*86400000 AS INTEGER),'chain.held',
|
|
1462
|
+
json_object('chain_id',NEW.chain_id,'message_id',NEW.message_id,'names',NEW.names,'handoff',NEW.handoff,'extra_rounds',NEW.extra_rounds));
|
|
1463
|
+
END;
|
|
1464
|
+
DROP TRIGGER IF EXISTS event_chain_released;
|
|
1465
|
+
CREATE TRIGGER event_chain_released AFTER DELETE ON free_chain_holds
|
|
1466
|
+
BEGIN
|
|
1467
|
+
INSERT INTO room_events (room_id,at,kind,data) SELECT OLD.room_id,CAST((julianday('now')-2440587.5)*86400000 AS INTEGER),'chain.released',
|
|
1468
|
+
json_object('chain_id',OLD.chain_id,'message_id',OLD.message_id) WHERE EXISTS (SELECT 1 FROM rooms WHERE id=OLD.room_id);
|
|
1469
|
+
END;
|
|
1470
|
+
DROP TRIGGER IF EXISTS event_scheduler_decided;
|
|
1471
|
+
CREATE TRIGGER event_scheduler_decided AFTER INSERT ON scheduler_decisions
|
|
1472
|
+
BEGIN
|
|
1473
|
+
INSERT INTO room_events (room_id,at,kind,data) VALUES (NEW.room_id,CAST((julianday('now')-2440587.5)*86400000 AS INTEGER),'scheduler.decided',
|
|
1474
|
+
json_object('decision_id',NEW.id,'after_message_id',NEW.after_message_id,'kind',NEW.kind,'label',NEW.label,
|
|
1475
|
+
'confidence',NEW.confidence,'applied',NEW.applied,'provider',NEW.provider));
|
|
1476
|
+
END;
|
|
1477
|
+
DROP TRIGGER IF EXISTS event_scheduler_applied;
|
|
1478
|
+
CREATE TRIGGER event_scheduler_applied AFTER UPDATE OF applied ON scheduler_decisions
|
|
1479
|
+
WHEN OLD.applied IS NOT NEW.applied
|
|
1480
|
+
BEGIN
|
|
1481
|
+
INSERT INTO room_events (room_id,at,kind,data) VALUES (NEW.room_id,CAST((julianday('now')-2440587.5)*86400000 AS INTEGER),'scheduler.applied',
|
|
1482
|
+
json_object('decision_id',NEW.id,'label',NEW.label,'applied',NEW.applied));
|
|
1483
|
+
END;
|
|
1484
|
+
DROP TRIGGER IF EXISTS event_discussion_created;
|
|
1485
|
+
CREATE TRIGGER event_discussion_created AFTER INSERT ON discussion_sessions
|
|
1486
|
+
BEGIN
|
|
1487
|
+
INSERT INTO room_events (room_id,at,kind,data) VALUES (NEW.room_id,CAST((julianday('now')-2440587.5)*86400000 AS INTEGER),'discussion.created',
|
|
1488
|
+
json_object('session_id',NEW.id,'status',NEW.status,'goal',substr(NEW.goal,1,80)));
|
|
1489
|
+
END;
|
|
1490
|
+
DROP TRIGGER IF EXISTS event_discussion_changed;
|
|
1491
|
+
CREATE TRIGGER event_discussion_changed AFTER UPDATE OF status ON discussion_sessions
|
|
1492
|
+
WHEN OLD.status IS NOT NEW.status
|
|
1493
|
+
BEGIN
|
|
1494
|
+
INSERT INTO room_events (room_id,at,kind,data) VALUES (NEW.room_id,CAST((julianday('now')-2440587.5)*86400000 AS INTEGER),'discussion.changed',
|
|
1495
|
+
json_object('session_id',NEW.id,'status',NEW.status,'from_status',OLD.status));
|
|
1496
|
+
END;
|