mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-11-04 19:28:46 +01:00
fix: use canonical conversation identity for native contracts
This commit is contained in:
1 parent
0d8ac2855e
commit
cdfd701d89
4 files changed
+24
-4
No files matched your search
@@ -2529,7 +2529,8 @@ wake from a server-verified human card response references that entry in
|
||||
`humanResponses`, whose answer is already present in the current request context.
|
||||
Agent/tool outcomes and generated summaries are not promoted to human direction.
|
||||
|
||||
Standing agent chats complete the current response stage. Each pending request
|
||||
Standing agent chats, identified by both conversation agent and user IDs through
|
||||
the shared conversation predicate, complete the current response stage. Each pending request
|
||||
keeps its criterion identity and source, with instructions to address it within
|
||||
that stage. Authorized chat actions require verified results. Delegation requires
|
||||
a verified handoff and a reply; the worker's task remains separate. An unavailable
|
||||
|
||||
@@ -2576,6 +2576,7 @@ export function heartbeatService(
|
||||
priority: issueContext.priority,
|
||||
workMode: issueContext.workMode,
|
||||
conversationAgentId: issueContext.conversationAgentId,
|
||||
conversationUserId: issueContext.conversationUserId,
|
||||
reviewPolicy: issueContext.reviewPolicy,
|
||||
description: issueContext.description,
|
||||
projectId: issueContext.projectId,
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
|
||||
describe("buildNativeCompletionContract", () => {
|
||||
it("scopes standing-chat criteria to the response while preserving every current request and source", () => {
|
||||
const issue = { id: "chat", title: "Chat with CEO", description: null, conversationAgentId: "ceo" };
|
||||
const issue = { id: "chat", title: "Chat with CEO", description: null, conversationAgentId: "ceo", conversationUserId: "operator" };
|
||||
const comments = [
|
||||
{ id: "operator-request", body: "Restart this instance." },
|
||||
{ id: "handoff-request", body: "Have Morgan draft the update and send it here when finished." },
|
||||
@@ -43,6 +43,22 @@ describe("buildNativeCompletionContract", () => {
|
||||
.toEqual([{ id: "objective", requirement: request }]);
|
||||
});
|
||||
|
||||
it.each([undefined, null])("keeps an agent-only issue in task and plan scope when its conversation user is %s", conversationUserId => {
|
||||
const request = "Write the launch plan and wait for approval.";
|
||||
const contract = buildNativeCompletionContract({ title: "Chat with CEO", description: null,
|
||||
conversationAgentId: "ceo", conversationUserId }, { immediateRequest: request });
|
||||
expect(contract.criteria).toEqual([{ id: "objective", requirement: request }]);
|
||||
expect(contract.objective).toContain("propose or save the requested plan and wait before executing");
|
||||
});
|
||||
|
||||
it.each([" Help plan the launch. ", null])("scopes a conversation's first turn without a follow-up (%s)", description => {
|
||||
const contract = buildNativeCompletionContract({ title: "Chat with CEO", description,
|
||||
conversationAgentId: "ceo", conversationUserId: "operator" });
|
||||
expect(contract.objective).toMatch(/current conversation response/i);
|
||||
expect(contract.criteria).toEqual([{ id: "objective", requirement:
|
||||
`Address this request in the current authorized conversation response: ${description?.trim() || "Respond to the current conversation context."}` }]);
|
||||
});
|
||||
|
||||
it("uses the task description as the single initial criterion", () => {
|
||||
expect(buildNativeCompletionContract({
|
||||
title: "Ship the runner",
|
||||
|
||||
@@ -6,6 +6,7 @@ import { completionContracts } from "@paperclipai/db";
|
||||
import type { NativeCompletionSource, StrictCompletionContractInput } from "../../vendor/paperclip-runner/index.js";
|
||||
|
||||
import { nativeSha256 } from "./canonical.js";
|
||||
import { isConversation, type ConversationIdentity } from "../agent-conversations.js";
|
||||
|
||||
export const NATIVE_COMPLETION_CONTRACT_SCHEMA = "paperclip.completion-contract.v1";
|
||||
export const NATIVE_COMPLETION_POLICY_VERSION = "phase6-v4";
|
||||
@@ -87,7 +88,7 @@ export function resolveNativeCompletionPolicy(issue: {
|
||||
}
|
||||
|
||||
export function buildNativeCompletionContract(
|
||||
issue: { title: string; description: string | null; conversationAgentId?: string | null },
|
||||
issue: { title: string; description: string | null } & ConversationIdentity,
|
||||
options: {
|
||||
readonly revision?: number;
|
||||
readonly immediateRequest?: string | null;
|
||||
@@ -104,7 +105,7 @@ export function buildNativeCompletionContract(
|
||||
.filter((request) => request.length > 0);
|
||||
const humanResponseId = options.humanResponseId?.trim();
|
||||
const hasFollowUp = immediateRequests.length > 0 || Boolean(humanResponseId);
|
||||
const conversation = Boolean(issue.conversationAgentId);
|
||||
const conversation = isConversation(issue);
|
||||
const requirement = (request: string) => conversation
|
||||
? `Address this request in the current authorized conversation response: ${request}`
|
||||
: request;
|
||||
@@ -165,6 +166,7 @@ export async function ensureNativeCompletionContract(input: {
|
||||
description: string | null;
|
||||
reviewPolicy?: string | null;
|
||||
conversationAgentId?: string | null;
|
||||
conversationUserId?: string | null;
|
||||
};
|
||||
actorId: string;
|
||||
immediateRequest?: string | null;
|
||||
|
||||
Reference in new issue
Block a user