feat: 完成 J 群組 — 委託子系統
Task 資料表與自然語句解析(單次提醒)、依原型的接案/觸發/逾期追擊演出、 委託與關係帳本/情緒的回饋迴路(含默契旗標)、主動關照(待辦偵測+作息交叉比對, 稀有度節流不重複台詞)、排程器可靠性(服務重啟後重新掃描 PENDING 任務掛回 JobQueue,逾期立即補觸發)。J.mjs 以 spawnSync 實際重啟服務驗證 J-7。 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
d82b834e47
commit
3503cc0be6
@@ -0,0 +1,70 @@
|
||||
import { Injectable, NotFoundException } from "@nestjs/common";
|
||||
import { PrismaService } from "../prisma/prisma.service.js";
|
||||
import { SentimentLedgerService } from "../relationship/sentiment-ledger.service.js";
|
||||
import { EmotionService } from "../emotion/emotion.service.js";
|
||||
import { TASK_LEDGER_EVENT, TASK_LEDGER_WEIGHT } from "./constants.js";
|
||||
|
||||
// J-5 任務與記憶、關係的迴路:完成/失敗誠實回報(引擎層),但角色演出可以是遺憾/得意的語氣。
|
||||
@Injectable()
|
||||
export class TaskFeedbackService {
|
||||
constructor(
|
||||
private readonly prisma: PrismaService,
|
||||
private readonly sentimentLedger: SentimentLedgerService,
|
||||
private readonly emotion: EmotionService,
|
||||
) {}
|
||||
|
||||
async complete(taskId: string, now: Date = new Date()) {
|
||||
const task = await this.prisma.client.task.findUnique({ where: { id: taskId } });
|
||||
if (!task) {
|
||||
throw new NotFoundException(`任務不存在:${taskId}`);
|
||||
}
|
||||
await this.prisma.client.task.update({
|
||||
where: { id: taskId },
|
||||
data: { status: "COMPLETED", completedAt: now },
|
||||
});
|
||||
await this.sentimentLedger.recordEvent(
|
||||
task.characterId,
|
||||
task.userId,
|
||||
TASK_LEDGER_EVENT.COMPLETED,
|
||||
TASK_LEDGER_WEIGHT.COMPLETED,
|
||||
{ now },
|
||||
);
|
||||
return this.prisma.client.task.findUnique({ where: { id: taskId } });
|
||||
}
|
||||
|
||||
async fail(taskId: string, now: Date = new Date()) {
|
||||
const task = await this.prisma.client.task.findUnique({ where: { id: taskId } });
|
||||
if (!task) {
|
||||
throw new NotFoundException(`任務不存在:${taskId}`);
|
||||
}
|
||||
await this.prisma.client.task.update({ where: { id: taskId }, data: { status: "FAILED" } });
|
||||
// 誠實回報失敗(引擎層行為固定),負向偏誤已由 E-2 機制放大,不需要在這裡重複加權。
|
||||
await this.sentimentLedger.recordEvent(
|
||||
task.characterId,
|
||||
task.userId,
|
||||
TASK_LEDGER_EVENT.FAILED,
|
||||
TASK_LEDGER_WEIGHT.FAILED,
|
||||
{ now },
|
||||
);
|
||||
return this.prisma.client.task.findUnique({ where: { id: taskId } });
|
||||
}
|
||||
|
||||
// 觸發後被忽視(追擊次數已達門檻仍無回應):輕微失落,且如實記錄一筆負向事件。
|
||||
async markIgnored(taskId: string, now: Date = new Date()) {
|
||||
const task = await this.prisma.client.task.findUnique({ where: { id: taskId } });
|
||||
if (!task) {
|
||||
throw new NotFoundException(`任務不存在:${taskId}`);
|
||||
}
|
||||
await this.sentimentLedger.recordEvent(
|
||||
task.characterId,
|
||||
task.userId,
|
||||
TASK_LEDGER_EVENT.IGNORED,
|
||||
TASK_LEDGER_WEIGHT.IGNORED,
|
||||
{ now },
|
||||
);
|
||||
await this.emotion.processInput(task.characterId, "", {
|
||||
now,
|
||||
baselineSignal: { tag: "SAD", intensity: 0.3 },
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user