@plainconceptsplatform/workflows 1.14.0 → 1.14.1

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.
@@ -29,19 +29,31 @@ jq -r --arg marker "$marker" --arg prefix "$comment_prefix" --arg issue "$issue_
29
29
  any(.items[]; .type == "update_issue");
30
30
 
31
31
  # A temporal draft is a replacement body the worker still expects to grow: the draft
32
- # marker distinguishes it from a finished body.
32
+ # marker distinguishes it from a finished body. The gh-aw process_safe_outputs strips
33
+ # HTML comments from the body, so the draft marker (<!-- agent-refine-draft -->) can
34
+ # be gone by the time the validator reads it (Bots #1336, run 42214146974). When the
35
+ # draft marker is absent but the pending mark (_pending see questions below_) is
36
+ # present, the body is still a draft: the pending mark only appears in drafts, and a
37
+ # finished body has none.
33
38
  def has_draft_body:
34
39
  any(.items[]; .type == "update_issue" and
35
40
  (.item_number == null or (.item_number | tostring) == $issue) and
36
41
  (.body | type == "string") and
37
- (.body | contains($draft_marker)));
42
+ ((.body | contains($draft_marker)) or (.body | contains($pending_mark))));
38
43
 
39
44
  # The batched questions, by the sentence that opens them. It decides the outcome on its own:
40
45
  # Bots #561, #871 and Numa #821 asked, left a draft without the draft marker, were read as
41
46
  # complete, and implement started two seconds later on a story nobody had answered.
47
+ # The prompt asks the model to open with the exact questions_line, but models paraphrase
48
+ # it: GLM-5-2 wrote "I have some questions that the code cannot settle on its own" and the
49
+ # exact-line match failed, dropping a valid questions outcome (Bots #1336). Match the exact
50
+ # line, or its opening "I have some questions" prefix, which is specific enough in a refine
51
+ # comment to never match the complete or split messages.
42
52
  def asks_questions:
43
53
  any(.items[]; .type == "add_comment" and (.item_number | tostring) == $issue and
44
- (.body | type == "string") and (.body | contains($questions_line)));
54
+ (.body | type == "string") and
55
+ ((.body | contains($questions_line)) or
56
+ (.body | test("I have some questions"; "i"))));
45
57
 
46
58
  def has_pending_marks:
47
59
  any(.items[]; .type == "update_issue" and
@@ -24,7 +24,10 @@ jq -r --arg pr "$pr_number" --slurpfile threads "$threads_file" '
24
24
  .items as $items
25
25
  | ($threads[0] | map(select(.isResolved == false and .isOutdated == false) | .id) | sort) as $expected
26
26
  | ($items | [.[] | select(.type == "add_comment" and (.item_number | tostring) == $pr and (.body | type == "string"))]) as $comments
27
- | ($comments | map(.body | if test("\\*\\*Review outcome:\\*\\*\\s*(implemented|already-satisfied|needs-human)"; "i") then capture("\\*\\*Review outcome:\\*\\*\\s*(?<v>implemented|already-satisfied|needs-human)"; "i").v | ascii_downcase else empty end) | .[0] // "invalid") as $outcome
27
+ # The line is matched by shape, not exact markdown: a model that writes
28
+ # **Review outcome** : implemented or **Review outcome - implemented still means
29
+ # the same. See the triage validator for the same pattern.
30
+ | ($comments | map(.body | if test("Review outcome[^\\w\\n]{0,6}(?<v>implemented|already-satisfied|needs-human)\\b"; "i") then capture("Review outcome[^\\w\\n]{0,6}(?<v>implemented|already-satisfied|needs-human)\\b"; "i").v | ascii_downcase else empty end) | .[0] // "invalid") as $outcome
28
31
  # `add` on an empty array is null, not [], and `unique` then dies with "Cannot iterate over
29
32
  # null". That is not an edge case: it is every pull-request-level review. Requesting changes
30
33
  # from the Files tab, or a plain review body with no inline comment, creates a review and no
@@ -20,12 +20,15 @@ fi
20
20
  # must contain a verdict line matching **Verdict:** pass|needs-info|needs-maintainer|block.
21
21
  # capture() returns an object use a named group (?<v>...) to extract the value.
22
22
  # test() before capture() avoids jq errors on non-matching bodies.
23
+ # The line is matched by shape, not exact markdown: a model that writes
24
+ # **Verdict** : pass or **Verdict - pass still means the same (Bots #1336 showed
25
+ # GLM-5-2 paraphrasing the expected sentence; the same happens with verdict lines).
23
26
  jq -r --arg issue "$issue_number" '
24
27
  def extract_verdict:
25
28
  [.items[] | select(.type == "add_comment" and (.item_number | tostring) == $issue and (.body | type == "string"))]
26
29
  | map(.body |
27
- if test("\\*\\*Verdict:\\*\\*\\s*(pass|needs-info|needs-maintainer|block)"; "i") then
28
- capture("\\*\\*Verdict:\\*\\*\\s*(?<v>pass|needs-info|needs-maintainer|block)"; "i").v | ascii_downcase
30
+ if test("Verdict[^\\w\\n]{0,6}(?<v>pass|needs-info|needs-maintainer|block)\\b"; "i") then
31
+ capture("Verdict[^\\w\\n]{0,6}(?<v>pass|needs-info|needs-maintainer|block)\\b"; "i").v | ascii_downcase
29
32
  else empty end
30
33
  )
31
34
  | .[0] // "none";
@@ -75,6 +75,16 @@ assert_output 'complete output cannot update another issue' invalid \
75
75
  '{"items":[{"type":"update_issue","item_number":42,"body":"# User story"},{"type":"update_issue","item_number":7,"body":"# Other story"}]}'
76
76
  assert_output 'draft update with questions comment is questions' questions \
77
77
  '{"items":[{"type":"update_issue","item_number":42,"body":"<!-- agent-refine-draft -->\n### Proposal\n_pending see questions below_"},{"type":"add_comment","item_number":42,"body":"<!-- agent-refine -->\nRefinement update\nI have some questions about this issue. Please reply in one comment and I''ll process your answers.\nWhich area owns this behavior?"}]}'
78
+
79
+ # From Bots #1336, run 42214146974. gh-aw process_safe_outputs strips HTML comments
80
+ # from the body, so the draft marker (<!-- agent-refine-draft -->) is gone. The
81
+ # model also paraphrased the questions line as "I have some questions that the code
82
+ # cannot settle on its own" instead of the exact sentence. The pending mark
83
+ # (_pending see questions below_) survives in the body and the comment is still on
84
+ # the source issue, so the outcome is questions, not invalid.
85
+ assert_output 'stripped draft marker with paraphrased questions is questions' questions \
86
+ '{"items":[{"type":"update_issue","item_number":42,"body":"**Complexity:** standard path\n\n> Refinement draft. Three open questions are in a separate comment. The parts they leave open are marked `_pending see questions below_`."},{"type":"add_comment","item_number":42,"body":"## Refinement update\n\nI have some questions that the code cannot settle on its own. Reply in one comment to change any of them.\n1. Does the conductor bot stay local only too?"}]}'
87
+
78
88
  assert_output 'draft update alone is invalid' invalid \
79
89
  '{"items":[{"type":"update_issue","item_number":42,"body":"<!-- agent-refine-draft -->\n### Proposal\n_pending see questions below_"}]}'
80
90
 
@@ -738,7 +738,20 @@ jobs:
738
738
  output_tokens=$(jq -r '.output_tokens // empty' usage-read/agent_usage.json 2>/dev/null || echo "")
739
739
  fi
740
740
  if [ -n "$output_tokens" ] && [ "$output_tokens" -gt 20000 ]; then
741
- echo "truncated=This attempt consumed ${output_tokens} output tokens and still produced no outcome. That is what provider output truncation looks like, not an outage: the model hit the single-response cap mid-generation and every call it was writing was lost. If this repeats, split the issue or tighten its body." >> "$GITHUB_OUTPUT"
741
+ # A run that burned tokens and produced items the validator refused is not
742
+ # truncation: the agent finished, and the validator did not recognise the
743
+ # outcome shape (Bots #1336, run 42214146974: 50926 output tokens, 2 items,
744
+ # draft marker stripped by process_safe_outputs, questions line paraphrased).
745
+ # Only call it truncation when the agent spent tokens and produced nothing.
746
+ item_count=0
747
+ if [ -f usage-read/agent_output.json ]; then
748
+ item_count=$(jq '.items | length' usage-read/agent_output.json 2>/dev/null || echo 0)
749
+ fi
750
+ if [ "$item_count" -gt 0 ]; then
751
+ echo "truncated=This attempt consumed ${output_tokens} output tokens and produced ${item_count} item(s), but the validator could not recognise the outcome. The agent finished its work: check the run artifacts (agent_output.json, safeoutputs.jsonl) against the validator's expected shape before retrying." >> "$GITHUB_OUTPUT"
752
+ else
753
+ echo "truncated=This attempt consumed ${output_tokens} output tokens and still produced no outcome. That is what provider output truncation looks like, not an outage: the model hit the single-response cap mid-generation and every call it was writing was lost. If this repeats, split the issue or tighten its body." >> "$GITHUB_OUTPUT"
754
+ fi
742
755
  else
743
756
  echo "truncated=" >> "$GITHUB_OUTPUT"
744
757
  fi
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plainconceptsplatform/workflows",
3
- "version": "1.14.0",
3
+ "version": "1.14.1",
4
4
  "description": "Install and update Platform GitHub agentic workflows.",
5
5
  "keywords": [
6
6
  "github-actions",