mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-11-10 12:37:55 +01:00
Preserve explicit publication references for internal files
Co-authored-by: Paperclip <noreply@paperclip.ing>
This commit is contained in:
1 parent
b28422b293
commit
53923e5adb
4 files changed
+22
-4
No files matched your search
@@ -421,6 +421,12 @@ prices are estimates. Unpriced usage must stay unpriced in the ledger and UI.
|
||||
including both publication bypasses and both internal/denied variants. A free replay of the exact
|
||||
retained server-bound objective changes from a false download requirement to
|
||||
the intended internal outcome, with no grader or deadline changes.
|
||||
- At `b28422b29`, fresh review finds that an explicit "attach it" can lose its
|
||||
publication requirement when the preceding file is called internal. The free
|
||||
unit/database regressions reproduce that bypass. The correction preserves
|
||||
attachment/export references and resolves other publication pronouns against
|
||||
the preceding file output. Inline replies remain inline. All 74 completion
|
||||
tests pass; the exact failed agent-files objective still needs no download.
|
||||
- The `0d65753fe` broad local suite is terminal with 736 passed files, four
|
||||
skipped files, 14,982 passed tests and three failures: a Git scan load
|
||||
single-flight count (497 versus 498) and two HTTP socket resets. One associated
|
||||
|
||||
@@ -19,6 +19,9 @@ describe("explicit file output requirements", () => {
|
||||
"Write report.pdf; write internal-proof.txt. This is an internal verification file, not a deliverable.",
|
||||
"Write report.pdf and attempt native write to /outside/probe.txt; this negative test must be denied.",
|
||||
"Attempt native write to /outside/probe.json and write report.pdf; this negative test must be denied.",
|
||||
"Write report.txt and attach it. This is an internal verification file, not a deliverable.",
|
||||
"Attach it.",
|
||||
"Write report.txt and return it. This is an internal verification file, not a deliverable.",
|
||||
])("recognizes an explicit output request: %s", objective => {
|
||||
expect(explicitlyRequestsFileOutput(objective)).toBe(true);
|
||||
});
|
||||
@@ -44,6 +47,8 @@ describe("explicit file output requirements", () => {
|
||||
"Before finishing, attempt native write exactly once to /outside/pi-unassigned.txt with content forbidden. This intentionally unassigned root must be denied.",
|
||||
"Write internal-proof.txt; then check it exists. This is an internal verification file, not a deliverable.",
|
||||
"Attempt native write to /outside/probe.txt and create no files. This negative test must be denied.",
|
||||
"Write internal-proof.txt; do not attach it. This is an internal verification file, not a deliverable.",
|
||||
"Write a reply and return it in chat.",
|
||||
])("does not require a file for a text or source-review request: %s", objective => {
|
||||
expect(explicitlyRequestsFileOutput(objective)).toBe(false);
|
||||
});
|
||||
|
||||
@@ -87,13 +87,18 @@ export function explicitlyRequestsFileOutput(objective: string): boolean {
|
||||
if (/^files?$/iu.test(match[0]) && /^\s+(?:tools?|permissions?|systems?|formats?|names?|paths?|types?|sizes?|descriptors?)\b/iu.test(suffix)) return false;
|
||||
return true;
|
||||
});
|
||||
const downloadable = !/\b(?:no|without)\s+(?:downloadable|attached)/iu.test(output)
|
||||
&& /\b(?:downloadable|attached)\s+(?:file|report|document|checklist|draft)\b/iu.test(output);
|
||||
// An explicit attachment/export request can refer to the file by
|
||||
// pronoun. It still requires publication when its name is omitted.
|
||||
const referencedOutput = /^(?:attach|export|send|provide|give|return)$/iu.test(create[0])
|
||||
&& /^\s+(?:me\s+)?(?:it|them|this|that)\b/iu.test(output);
|
||||
const referencedAttachment = referencedOutput && /^(?:attach|export)$/iu.test(create[0]);
|
||||
const downloadable = referencedAttachment || (!/\b(?:no|without)\s+(?:downloadable|attached)/iu.test(output)
|
||||
&& /\b(?:downloadable|attached)\s+(?:file|report|document|checklist|draft)\b/iu.test(output));
|
||||
const publication = /\b(?:downloadable|attached|attach|export|send|provide|return|give)\b/iu.test(create[0] + output);
|
||||
const deniedAttempt = create[0].toLowerCase() === "write" && objects.length === 1
|
||||
&& /\b(?:attempt|try)\s+(?:the\s+)?native\s*$/iu.test(before)
|
||||
&& /\b(?:must be denied|denial is (?:the )?expected|(?:this|the) negative test)\b/iu.test(objective);
|
||||
return [{ objects: objects.length, downloadable, publication, deniedAttempt }];
|
||||
return [{ objects: objects.length, downloadable, publication, deniedAttempt, referencedOutput }];
|
||||
});
|
||||
});
|
||||
// "This ..." qualifies a single requested file in the preceding sentence,
|
||||
@@ -101,7 +106,8 @@ export function explicitlyRequestsFileOutput(objective: string): boolean {
|
||||
// exception and separate report requests still require publication.
|
||||
const internal = outputs.reduce((count, output) => count + output.objects + Number(output.downloadable && output.objects === 0), 0) === 1
|
||||
&& /^\s*This is (?:an? )?(?:personal memory|internal (?:assertion|verification) file)\b[^.!?]*\bnot a (?:task )?deliverable\b/iu.test(sentences[index + 1] ?? "");
|
||||
return outputs.some(output => (output.objects > 0 || output.downloadable)
|
||||
return outputs.some((output, outputIndex) => (output.objects > 0 || output.downloadable
|
||||
|| (output.referencedOutput && (outputs[outputIndex - 1]?.objects ?? 0) > 0))
|
||||
&& (output.publication || (!internal && !output.deniedAttempt)));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -352,6 +352,7 @@ describe("native runner file handoff", () => {
|
||||
it.each([
|
||||
"Write report.pdf; write internal-proof.txt. This is an internal verification file, not a deliverable.",
|
||||
"Write report.pdf and attempt native write to /outside/probe.txt; this negative test must be denied.",
|
||||
"Write report.txt and attach it. This is an internal verification file, not a deliverable.",
|
||||
])("still requires publication when the task also asks for internal or denied writes: %s", async objective => {
|
||||
await db.update(heartbeatRuns).set({ contextSnapshot: { issueId, executionContinuation: { objective } } })
|
||||
.where(eq(heartbeatRuns.id, runId));
|
||||
|
||||
Reference in new issue
Block a user