mirror of
https://github.com/multica-ai/multica.git
synced 2026-07-26 04:25:46 +02:00
Builds on PR 0.5's helper extraction. The dispatcher now skips
sections each task kind doesn't need, per Eve's Section × Kind
matrix on MUL-3560.
Measured impact (claude provider, full fixture with 2 repos + 10
skills, comparing PR 0.5 ↔ PR 0.6):
kind PR 0.5 PR 0.6 Δ Δ%
------------------------------------------------------------
comment-triggered 19462 19462 0 0%
assignment-triggered 18034 18034 0 0%
autopilot-run-only 11174 8442 -2732 -24%
quick-create 12497 4799 -7698 -62%
chat 11155 8423 -2732 -24%
✓ comment / assignment unchanged this PR (their diet comes from
the per-section compression PRs #1..#9 on the roadmap)
✓ quick-create from 12.5k → 4.8k chars (-62%)
✓ autopilot and chat from 11k → 8k chars (-24% each)
The matrix encoded in `buildMetaSkillContent`:
Section | comment | assign | autopilot | quick_create | chat
----------------------+---------+--------+-----------+--------------+------
Available Commands | full | full | full | minimal | full
Comment Formatting | ✓ | ✓ | — | — | —
Repositories | △ | △ | △ | — | △
Project Context | △ | △ | — | — | —
Issue Metadata | ✓ | ✓ | — | — | —
Instruction Precedence| — | ✓ | — | — | —
Sub-issue Creation | ✓ | ✓ | — | — | —
Skills | ✓ | ✓ | ✓ | — | ✓
Mentions | ✓ | ✓ | — | — | —
Attachments | ✓ | ✓ | — | — | —
What changed:
- runtime_config.go: the dispatcher now decides per kind which
helpers to call. Always-on prelude unchanged. The matrix above
is documented inline on `buildMetaSkillContent` and is the
single source of truth.
- runtime_config_sections.go: new `writeAvailableCommandsQuickCreate`
helper — emits only the `issue create` line plus the
`multica --help` escape hatch (~500 chars vs ~4400 for the full
variant). Used only when classifyTask returns kindQuickCreate.
- runtime_config_kind.go: `hasIssueContext` doc comment narrowed
to the three real call sites (Project Context, Issue Metadata,
Sub-issue Creation) per GPT-Boy's PR 0.5 review nit.
- runtime_config_kind_test.go:
* TestBuildMetaSkillContentKindMatrix updated to encode the new
expected section set per kind. Heading match tightened so it
only fires on the heading line, not inline references like
"See ## Comment Formatting below" inside Available Commands.
* TestBuildMetaSkillContentQuickCreateAvailableCommands (new)
locks the minimal-variant content: `issue create` is present,
every other Core command — get / status / metadata / comment
add / children / repo checkout / squad — is asserted absent.
- execenv_test.go: TestInjectRuntimeConfigIssueMetadataSectionScope
now expects the metadata Core discovery lines to be ABSENT for
quick-create (it uses the minimal Available Commands) and
PRESENT for every other kind. Comment narrowed to match.
Verification:
- go vet ./internal/daemon/... ok
- go test ./internal/daemon/... ./internal/handler/... ok
Backwards compatibility:
- InjectRuntimeConfig signature unchanged (still 2-tuple).
- No new daemon flags, no new ctx fields, no per-provider changes.
- Reverting this commit restores PR 0.5 byte-for-byte; the change
is contained inside buildMetaSkillContent's section selection.
Risk and follow-up:
- comment-triggered and assignment-triggered still ~19k each;
their reduction lands in PRs #1 (Available Commands compression),
#4 (Mentions compression), #5 (Issue Metadata compression).
- The full Available Commands variant retains "See ## Comment
Formatting below" as an inline reference, which is now a
dangling pointer for autopilot/chat where Comment Formatting is
gated out. Cleanup deferred to PR #1 of the roadmap (Available
Commands compression) — addressing it requires kind-specific
Available Commands variants, which is exactly that PR's
surface.
Co-authored-by: multica-agent <github@multica.ai>
111 lines
4.6 KiB
Go
111 lines
4.6 KiB
Go
package execenv
|
|
|
|
// taskKind labels the dispatch path that `buildMetaSkillContent` should follow
|
|
// for a given TaskContextForEnv. Today the brief contains several conditional
|
|
// sections gated by ad-hoc `ctx.ChatSessionID != ""` / `hasIssueContext` /
|
|
// `isAssignmentTriggered` checks scattered through `buildMetaSkillContent`.
|
|
// Centralising the classification into a single enum + helper gives every
|
|
// section a named axis to switch on (instead of re-deriving it from four
|
|
// pointers in each call site) and lets follow-up work apply strict per-kind
|
|
// gating without scattering more `if`s.
|
|
//
|
|
// This file is the structural prep for MUL-3560 PR 0.5 — see Eve's design
|
|
// reply on that issue:
|
|
//
|
|
// - kind classification: this file
|
|
// - per-section extraction + kind-driven dispatch in buildMetaSkillContent:
|
|
// runtime_config.go / runtime_config_sections.go
|
|
//
|
|
// The follow-up PR (0.6) will start removing sections that a given kind does
|
|
// not need (e.g. Mentions / Comment Formatting / Issue Metadata / Sub-issue
|
|
// out of quick-create); this PR keeps brief output byte-for-byte identical to
|
|
// the pre-refactor builder for every existing fixture so the refactor risk is
|
|
// isolated from the content-gating risk.
|
|
type taskKind int
|
|
|
|
const (
|
|
// kindCommentTriggered: a NEW comment on an issue triggered this run.
|
|
// `ctx.TriggerCommentID != ""` AND none of the chat / quick-create /
|
|
// autopilot fields are set. By far the most common kind.
|
|
kindCommentTriggered taskKind = iota
|
|
|
|
// kindAssignmentTriggered: an assignee was set / changed on an issue
|
|
// and the daemon fired a fresh run for the new assignee. No trigger
|
|
// comment, no chat / quick-create / autopilot context.
|
|
kindAssignmentTriggered
|
|
|
|
// kindAutopilotRunOnly: an autopilot fired in run-only mode (no issue
|
|
// is created or attached to this run; `ctx.AutopilotRunID != ""`).
|
|
kindAutopilotRunOnly
|
|
|
|
// kindQuickCreate: one-shot "create an issue from a natural-language
|
|
// prompt" task (`ctx.QuickCreatePrompt != ""`). There is no existing
|
|
// issue; the agent runs `multica issue create` exactly once and exits.
|
|
kindQuickCreate
|
|
|
|
// kindChat: interactive chat session (`ctx.ChatSessionID != ""`); no
|
|
// issue, no autopilot, no quick-create prompt.
|
|
kindChat
|
|
)
|
|
|
|
// classifyTask maps a TaskContextForEnv to the single taskKind that the brief
|
|
// should be assembled for. The ordering of the checks is the established
|
|
// precedence rule from the pre-refactor `buildMetaSkillContent`:
|
|
//
|
|
// 1. chat wins (ChatSessionID is the most-specific flag and runtime owners
|
|
// gate everything else off "not a chat" in the old code),
|
|
// 2. then quick-create,
|
|
// 3. then autopilot run-only,
|
|
// 4. then comment-triggered,
|
|
// 5. otherwise assignment-triggered.
|
|
//
|
|
// All five kinds are mutually exclusive at the call site that builds
|
|
// TaskContextForEnv — the daemon never sets two of ChatSessionID /
|
|
// QuickCreatePrompt / AutopilotRunID at once, and a comment trigger always
|
|
// implies an existing issue (TriggerCommentID is empty for on-assign). The
|
|
// precedence rule above is documented here only so a future caller that
|
|
// breaks the mutex by accident still falls into a deterministic kind instead
|
|
// of silently picking up the wrong workflow.
|
|
func classifyTask(ctx TaskContextForEnv) taskKind {
|
|
switch {
|
|
case ctx.ChatSessionID != "":
|
|
return kindChat
|
|
case ctx.QuickCreatePrompt != "":
|
|
return kindQuickCreate
|
|
case ctx.AutopilotRunID != "":
|
|
return kindAutopilotRunOnly
|
|
case ctx.TriggerCommentID != "":
|
|
return kindCommentTriggered
|
|
default:
|
|
return kindAssignmentTriggered
|
|
}
|
|
}
|
|
|
|
// hasIssueContext returns true for the kinds that operate on a real Multica
|
|
// issue and therefore can read / pin issue-scoped state. As of MUL-3560
|
|
// PR 0.6 the dispatcher gates these sections on this predicate:
|
|
//
|
|
// - Project Context
|
|
// - Issue Metadata
|
|
// - Sub-issue Creation
|
|
//
|
|
// All three are meaningless without an issue id and would either render an
|
|
// empty body or steer the agent into a guaranteed-failed CLI call. Mentions
|
|
// / Comment Formatting / Attachments are NOT gated by this predicate even
|
|
// though they look similar — those have their own dispatch rule because
|
|
// they care about whether the kind posts a comment, not whether it has an
|
|
// issue id (see runtime_config.go).
|
|
//
|
|
// Equivalent to the pre-refactor scattered check
|
|
// `ctx.ChatSessionID == "" && ctx.QuickCreatePrompt == "" && ctx.AutopilotRunID == ""`
|
|
// — extracted so the predicate has a name and every call site agrees on its
|
|
// meaning.
|
|
func (k taskKind) hasIssueContext() bool {
|
|
switch k {
|
|
case kindCommentTriggered, kindAssignmentTriggered:
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|