Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/skills/agentic-workflows/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ This skill is a dispatcher: identify the task type, load the matching workflow p
Read only the files you need:
Load these files from `github/gh-aw` (they are not available locally).
- `.github/aw/agentic-chat.md`
- `.github/aw/agentic-workflows-mcp.md`
- `.github/aw/asciicharts.md`
- `.github/aw/campaign.md`
- `.github/aw/charts-trending.md`
Expand All @@ -27,6 +28,7 @@ Load these files from `github/gh-aw` (they are not available locally).
- `.github/aw/github-agentic-workflows.md`
- `.github/aw/github-mcp-server.md`
- `.github/aw/llms.md`
- `.github/aw/mcp-clis.md`
- `.github/aw/memory.md`
- `.github/aw/messages.md`
- `.github/aw/network.md`
Expand Down
67 changes: 41 additions & 26 deletions pkg/parser/schema_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -491,17 +491,17 @@ func TestValidateMainWorkflowFrontmatterWithSchemaAndLocation_ToolsEditBoolean(t
}
}

func TestValidateMainWorkflowFrontmatterWithSchemaAndLocation_MaxEffectiveTokensIntegerZeroAllowed(t *testing.T) {
func TestValidateMainWorkflowFrontmatterWithSchemaAndLocation_MaxEffectiveTokensZeroInvalid(t *testing.T) {
t.Parallel()

validFrontmatter := map[string]any{
invalidFrontmatter := map[string]any{
"on": "push",
"max-effective-tokens": 0,
}

err := ValidateMainWorkflowFrontmatterWithSchemaAndLocation(validFrontmatter, "/tmp/gh-aw/max-effective-tokens-zero-integer-test.md")
if err != nil {
t.Fatalf("expected max-effective-tokens=0 to pass schema validation, got: %v", err)
err := ValidateMainWorkflowFrontmatterWithSchemaAndLocation(invalidFrontmatter, "/tmp/gh-aw/max-effective-tokens-zero-integer-test.md")
if err == nil {
t.Fatal("expected max-effective-tokens=0 to fail schema validation")
}
}

Expand Down Expand Up @@ -535,46 +535,61 @@ func TestValidateMainWorkflowFrontmatterWithSchemaAndLocation_MaxLimitsAllowExpr
}
}

func TestValidateMainWorkflowFrontmatterWithSchemaAndLocation_MaxLimitsRejectSuffixStrings(t *testing.T) {
func TestValidateMainWorkflowFrontmatterWithSchemaAndLocation_MaxLimitsAllowSuffixStrings(t *testing.T) {
t.Parallel()

invalidFrontmatter := map[string]any{
validFrontmatter := map[string]any{
"on": "push",
"max-effective-tokens": "100M",
"max-daily-effective-tokens": "100000K",
"max-daily-effective-tokens": "100k",
}

err := ValidateMainWorkflowFrontmatterWithSchemaAndLocation(invalidFrontmatter, "/tmp/gh-aw/max-limits-suffix-test.md")
if err == nil {
t.Fatal("expected max-effective-tokens/max-daily-effective-tokens suffix strings to fail schema validation")
err := ValidateMainWorkflowFrontmatterWithSchemaAndLocation(validFrontmatter, "/tmp/gh-aw/max-limits-suffix-test.md")
if err != nil {
t.Fatalf("expected max-effective-tokens/max-daily-effective-tokens suffix strings to pass schema validation, got: %v", err)
}
}

func TestValidateMainWorkflowFrontmatterWithSchemaAndLocation_MaxEffectiveTokensNegativeInvalid(t *testing.T) {
func TestValidateMainWorkflowFrontmatterWithSchemaAndLocation_MaxLimitsAllowSuffixStringsCaseVariants(t *testing.T) {
t.Parallel()

invalidFrontmatter := map[string]any{
validFrontmatter := map[string]any{
"on": "push",
"max-effective-tokens": "100k",
"max-daily-effective-tokens": "100M",
}
Comment on lines +556 to +560

err := ValidateMainWorkflowFrontmatterWithSchemaAndLocation(validFrontmatter, "/tmp/gh-aw/max-limits-suffix-case-variants-test.md")
if err != nil {
t.Fatalf("expected max-effective-tokens/max-daily-effective-tokens suffix case variants to pass schema validation, got: %v", err)
}
}

func TestValidateMainWorkflowFrontmatterWithSchemaAndLocation_MaxEffectiveTokensNegativeAllowed(t *testing.T) {
t.Parallel()

validFrontmatter := map[string]any{
"on": "push",
"max-effective-tokens": -1,
}

err := ValidateMainWorkflowFrontmatterWithSchemaAndLocation(invalidFrontmatter, "/tmp/gh-aw/max-effective-tokens-negative-test.md")
if err == nil {
t.Fatal("expected negative max-effective-tokens to fail schema validation")
err := ValidateMainWorkflowFrontmatterWithSchemaAndLocation(validFrontmatter, "/tmp/gh-aw/max-effective-tokens-negative-test.md")
if err != nil {
t.Fatalf("expected negative max-effective-tokens to pass schema validation, got: %v", err)
}
}

func TestValidateMainWorkflowFrontmatterWithSchemaAndLocation_MaxDailyEffectiveTokensIntegerZeroAllowed(t *testing.T) {
func TestValidateMainWorkflowFrontmatterWithSchemaAndLocation_MaxDailyEffectiveTokensZeroInvalid(t *testing.T) {
t.Parallel()

validFrontmatter := map[string]any{
invalidFrontmatter := map[string]any{
"on": "push",
"max-daily-effective-tokens": 0,
}

err := ValidateMainWorkflowFrontmatterWithSchemaAndLocation(validFrontmatter, "/tmp/gh-aw/max-daily-effective-tokens-zero-integer-test.md")
if err != nil {
t.Fatalf("expected max-daily-effective-tokens=0 to pass schema validation, got: %v", err)
err := ValidateMainWorkflowFrontmatterWithSchemaAndLocation(invalidFrontmatter, "/tmp/gh-aw/max-daily-effective-tokens-zero-integer-test.md")
if err == nil {
t.Fatal("expected max-daily-effective-tokens=0 to fail schema validation")
}
}

Expand All @@ -592,17 +607,17 @@ func TestValidateMainWorkflowFrontmatterWithSchemaAndLocation_MaxDailyEffectiveT
}
}

func TestValidateMainWorkflowFrontmatterWithSchemaAndLocation_MaxDailyEffectiveTokensNegativeInvalid(t *testing.T) {
func TestValidateMainWorkflowFrontmatterWithSchemaAndLocation_MaxDailyEffectiveTokensNegativeAllowed(t *testing.T) {
t.Parallel()

invalidFrontmatter := map[string]any{
validFrontmatter := map[string]any{
"on": "push",
"max-daily-effective-tokens": -1,
}

err := ValidateMainWorkflowFrontmatterWithSchemaAndLocation(invalidFrontmatter, "/tmp/gh-aw/max-daily-effective-tokens-negative-test.md")
if err == nil {
t.Fatal("expected negative max-daily-effective-tokens to fail schema validation")
err := ValidateMainWorkflowFrontmatterWithSchemaAndLocation(validFrontmatter, "/tmp/gh-aw/max-daily-effective-tokens-negative-test.md")
if err != nil {
t.Fatalf("expected negative max-daily-effective-tokens to pass schema validation, got: %v", err)
}
}

Expand Down
54 changes: 23 additions & 31 deletions pkg/parser/schemas/main_workflow_schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -3690,12 +3690,12 @@
"examples": [15, "${{ inputs.max-turns }}"]
},
"max-effective-tokens": {
"$ref": "#/$defs/templatable_integer",
"$ref": "#/$defs/max_effective_tokens_limit",
"default": 25000000,
"description": "Explicit ET budget control for firewall cost enforcement. Defaults to 25000000 when omitted. Supports GitHub Actions expressions."
},
"max-daily-effective-tokens": {
"$ref": "#/$defs/templatable_integer",
"$ref": "#/$defs/max_daily_effective_tokens_limit",

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot refactor and reuse same def

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactored to reuse a shared schema def (positive_effective_tokens_limit) across both token-limit fields in commit 4f94739.

"description": "24-hour effective-token guardrail for runs triggered by the same user. Omit the field to leave the guardrail disabled. Supports GitHub Actions expressions."
},
"max-runs": {
Expand Down Expand Up @@ -10542,50 +10542,42 @@
],
"description": "Positive integer as a string (supports optional K/M suffix) or a GitHub Actions expression."
},
"max_effective_tokens_limit": {
"positive_effective_tokens_limit": {
"oneOf": [
{
"type": "integer",
"not": {
"enum": [0]
},
"description": "Maximum effective-token (ET) budget for AWF API proxy enforcement. Use a negative value to disable budget enforcement and token steering."
"minimum": 1
},
{
"allOf": [
{
"$ref": "#/$defs/positive_integer_with_km_suffix_or_expression"
}
],
"description": "Maximum effective-token (ET) budget as a numeric string (supports K/M suffix) or GitHub Actions expression."
"$ref": "#/$defs/positive_integer_with_km_suffix_or_expression"
}
]
},
"max_effective_tokens_limit": {
"description": "Maximum effective-token (ET) budget for AWF API proxy enforcement. Accepts positive integers (including K/M suffix strings and expressions). Use a negative integer to disable budget enforcement and token steering.",
"oneOf": [
{
"$ref": "#/$defs/positive_effective_tokens_limit"
},
{
"type": "integer",
"maximum": -1
}
]
},
"max_daily_effective_tokens_limit": {
"description": "Maximum effective-token budget allowed across the last 24 hours for runs of this workflow by the triggering user. Accepts positive integers (including K/M suffix strings and expressions). Set to -1 to disable.",
"oneOf": [
{
"$ref": "#/$defs/positive_effective_tokens_limit"
},
{
"type": "integer",
"oneOf": [
{
"const": -1
},
{
"minimum": 1
}
],
"description": "Maximum effective-token budget allowed across the last 24 hours for runs of this workflow by the triggering user. Set to -1 to disable."
"const": -1
},
{
"type": "string",
"oneOf": [
{
"pattern": "^-1$"
},
{
"$ref": "#/$defs/positive_integer_with_km_suffix_or_expression"
}
],
"description": "Maximum 24-hour per-workflow effective-token budget as a numeric string (supports K/M suffix) or GitHub Actions expression. Use -1 to disable."
"pattern": "^-1$"
}
]
},
Expand Down