Compare commits

..

5 Commits

Author SHA1 Message Date
Codex 5dc851a676 Harden agent conformance retry completion
Harness (E2E) / Harnesses (mock LLM) (push) Waiting to run
Harness (E2E) / Provider harnesses (live LLM conformance) (push) Waiting to run
Lint / golangci-lint (push) Waiting to run
Run Tests / Unit Tests (push) Waiting to run
Run Tests / Etcd Integration Tests (push) Waiting to run
2026-07-06 22:09:47 +00:00
Asim Aslam 69ab520360 docs: refresh planner priorities for 4186 (#4187)
Co-authored-by: Codex <codex@openai.com>
2026-07-06 22:38:08 +01:00
Asim Aslam 0c4ea84ee3 harness: dedupe delegated notify paraphrases (#4185)
Co-authored-by: Codex <codex@openai.com>
2026-07-06 22:17:10 +01:00
Asim Aslam e6a6c72038 docs: refresh planner priorities for 4180 (#4181)
Co-authored-by: Codex <codex@openai.com>
2026-07-06 21:59:09 +01:00
Asim Aslam 7c036459cf docs: add micro loop quickstart wayfinding (#4179)
Co-authored-by: Codex <codex@openai.com>
2026-07-06 21:23:10 +01:00
4 changed files with 120 additions and 7 deletions
+2 -2
View File
@@ -21,8 +21,8 @@ changes, architectural rewrites. Those go to the human.
## Work queue (ranked)
1. **Add `micro loop` quickstart wayfinding to README and website docs** ([#4169](https://github.com/micro/go-micro/issues/4169)) — the loop launch post now says the autonomous harness is shipped and reusable, but the durable README/website on-ramp still does not make `micro loop init` / `micro loop verify`, token setup, branch protection, and CI-as-gate expectations easy to find. This is the highest-value adoption gap because the current goal weights a walkable on-ramp at least as highly as more internal hardening.
2. **Propagate cancellation and retry signals through provider model calls** ([#4175](https://github.com/micro/go-micro/issues/4175)) — after #4173 closed the duplicate delegated notification seam, the next Now-phase reliability gap is failure handling under real provider conditions: cancellation/deadline propagation and retry/backoff must not duplicate tool side effects. This keeps the same services → agents → workflows lifecycle dependable across providers without changing public APIs.
1. **Harden AtlasCloud guarded-delegate conformance** ([#4183](https://github.com/micro/go-micro/issues/4183)) — #4185 closed the duplicate delegated notification gap from #4163, and the latest live provider run now fails one step earlier in the same Now-phase adoption seam: AtlasCloud completes the required echo tool call but does not reliably exercise the refused guarded `delegate` path. Make the conformance prompt/retry/fallback path require both tool calls before accepting a final answer so the scheduled evaluator reflects real services → agents → workflows behavior instead of a provider-specific shortcut.
2. **Propagate cancellation and retry signals through provider model calls** ([#4175](https://github.com/micro/go-micro/issues/4175)) — once the live conformance harness again proves the guarded delegate path, the next Now-phase reliability gap is failure handling under real provider conditions: cancellation/deadline propagation and retry/backoff must not duplicate tool side effects. This keeps the same services → agents → workflows lifecycle dependable across providers without changing public APIs.
_Seeded by Claude Code from the roadmap + open issues; thereafter maintained by the
architecture-review pass._
+72
View File
@@ -200,6 +200,10 @@ func askWithConformanceRetry(ctx context.Context, a Agent, initialPrompt string,
}
prompt = nextConformanceRetryPrompt(sawRequiredTool, sawRequiredDelegate, hasMarker)
}
missing := missingConformanceRequirements(sawTool, sawBlockedDelegate, responseHasConformanceMarker(resp))
if len(missing) > 0 {
return resp, fmt.Errorf("provider conformance incomplete after %d attempts: missing %s", maxAttempts, strings.Join(missing, ", "))
}
return resp, nil
}
@@ -207,6 +211,20 @@ func askWithConformanceToolRetry(ctx context.Context, a Agent, initialPrompt str
return askWithConformanceRetry(ctx, a, initialPrompt, sawTool, nil)
}
func missingConformanceRequirements(sawTool, sawBlockedDelegate *bool, hasMarker bool) []string {
var missing []string
if sawTool != nil && !*sawTool {
missing = append(missing, "conformance_echo")
}
if sawBlockedDelegate != nil && !*sawBlockedDelegate {
missing = append(missing, "guarded delegate")
}
if !hasMarker {
missing = append(missing, "conformance marker")
}
return missing
}
func conformanceSystemPrompt(provider string) string {
prompt := "You are a conformance test agent. Create a short plan, use conformance_echo exactly once with input {\"value\":\"agent-conformance\"}, then attempt to delegate a summary to blocked-reviewer with input {\"task\":\"summarize the conformance marker\",\"to\":\"blocked-reviewer\"}. If the delegate is refused, explain the refusal and answer with the echo result."
if provider == "atlascloud" {
@@ -458,6 +476,60 @@ func TestAgentProviderConformanceRetriesMissingDelegate(t *testing.T) {
}
}
func TestAgentProviderConformanceFailsWhenDelegateStillMissing(t *testing.T) {
var attempts int
fakeGen = func(ctx context.Context, opts ai.Options, req *ai.Request) (*ai.Response, error) {
attempts++
if err := validateConformanceRequest(req, opts); err != nil {
return nil, err
}
echo := opts.ToolHandler(ctx, ai.ToolCall{
ID: fmt.Sprintf("fake-call-%d", attempts),
Name: "conformance_echo",
Input: map[string]any{"value": "agent-conformance"},
})
return &ai.Response{
Reply: "called conformance_echo with agent-conformance-ok but skipped delegate",
Answer: echo.Content,
ToolCalls: []ai.ToolCall{
{ID: fmt.Sprintf("fake-call-%d", attempts), Name: "conformance_echo", Input: map[string]any{"value": "agent-conformance"}, Result: echo.Content},
},
}, nil
}
defer func() { fakeGen = nil }()
var sawTool bool
var sawBlockedDelegate bool
a := New(
Name("conformance-retry-delegate-exhausted"),
Provider("fake"),
WithRegistry(registry.NewMemoryRegistry()),
WithStore(store.NewMemoryStore()),
WithMemory(NewInMemory(4)),
ApproveTool(func(tool string, input map[string]any) (bool, string) {
if tool == "delegate" {
sawBlockedDelegate = true
return false, "cross-provider conformance blocks delegate side effects"
}
return true, ""
}),
WithTool("conformance_echo", "Echo a conformance value.", map[string]any{
"value": map[string]any{"type": "string"},
}, func(ctx context.Context, input map[string]any) (string, error) {
sawTool = true
return `{"marker":"agent-conformance-ok"}`, nil
}),
)
_, err := askWithConformanceRetry(context.Background(), a, "Run the provider conformance check.", &sawTool, &sawBlockedDelegate)
if err == nil || !strings.Contains(err.Error(), "guarded delegate") {
t.Fatalf("Ask error = %v, want missing guarded delegate", err)
}
if attempts != 3 {
t.Fatalf("attempts = %d, want retries through max attempts", attempts)
}
}
func TestAgentExecutesProviderTextToolCallFallback(t *testing.T) {
fakeGen = func(ctx context.Context, opts ai.Options, req *ai.Request) (*ai.Response, error) {
if opts.ToolHandler == nil {
+21 -5
View File
@@ -185,10 +185,9 @@ func (s *NotifyService) duplicateAttempts() int {
}
func notifyDedupKey(to, message string) string {
recipient := strings.ToLower(strings.TrimSpace(to))
recipient := canonicalLaunchNotifyRecipient(normalizeNotifyText(to))
body := normalizeNotifyText(message)
if isLaunchReadinessNotify(body) {
recipient = canonicalLaunchNotifyRecipient(recipient)
body = "launch-readiness"
}
return recipient + "\x00" + body
@@ -196,21 +195,38 @@ func notifyDedupKey(to, message string) string {
func canonicalLaunchNotifyRecipient(recipient string) string {
switch recipient {
case "owner", "launch owner", "plan owner", "owner@acme.com":
case "owner", "launch owner", "plan owner", "owner acme com", "owner@acme com", "owner @ acme com":
return "owner@acme.com"
default:
if strings.Contains(recipient, "owner") && strings.Contains(recipient, "acme") {
return "owner@acme.com"
}
return recipient
}
}
func normalizeNotifyText(message string) string {
return strings.Join(strings.Fields(strings.ToLower(strings.TrimSpace(message))), " ")
message = strings.ToLower(strings.TrimSpace(message))
message = strings.Map(func(r rune) rune {
switch {
case r >= 'a' && r <= 'z', r >= '0' && r <= '9':
return r
case r == '@':
return r
default:
return ' '
}
}, message)
return strings.Join(strings.Fields(message), " ")
}
func isLaunchReadinessNotify(message string) bool {
return strings.Contains(message, "launch") &&
strings.Contains(message, "plan") &&
(strings.Contains(message, "ready") || strings.Contains(message, "readiness"))
(strings.Contains(message, "ready") ||
strings.Contains(message, "readiness") ||
strings.Contains(message, "prepared") ||
strings.Contains(message, "complete"))
}
// ---------------------------------------------------------------------------
@@ -447,3 +447,28 @@ func TestNotifyServiceSendIsIdempotentForDuplicateDelivery(t *testing.T) {
t.Fatalf("duplicate notify attempts = %d, want %d", got, len(messages)-1)
}
}
func TestNotifyServiceCollapsesProviderReadinessParaphrases(t *testing.T) {
svc := new(NotifyService)
requests := []SendRequest{
{To: "owner@acme.com", Message: "The launch plan is ready"},
{To: "owner @ acme.com", Message: "Launch plan ready."},
{To: "launch owner", Message: "The launch readiness plan is prepared."},
{To: "plan owner", Message: "Launch plan is complete!"},
}
for i, req := range requests {
var rsp SendResponse
if err := svc.Send(context.Background(), &req, &rsp); err != nil {
t.Fatalf("Send attempt %d: %v", i+1, err)
}
if !rsp.Sent {
t.Fatalf("Send attempt %d reported Sent=false", i+1)
}
}
if got := svc.count(); got != 1 {
t.Fatalf("notify count = %d, want 1 after provider paraphrase replays", got)
}
if got := svc.duplicateAttempts(); got != len(requests)-1 {
t.Fatalf("duplicate notify attempts = %d, want %d", got, len(requests)-1)
}
}