Skip to content

Commit c14a886

Browse files
authored
Remove skill content max truncation (#4639)
Remove `max` from the skills metadata contract and stop truncating skill content in `use_skill`. Agents now receive complete skill instructions instead of partial directives plus truncation warnings. ## Root Cause `use_skill` historically sliced skill markdown to `meta.max` before inserting the skill instructions into context. Long skills therefore loaded as incomplete directives, causing agents to complain about truncation and potentially follow partial workflows. ## Approach - Remove the skill-level `max` field from parsed preamble metadata, extracted metadata, and `SkillMeta`. - Remove the `use_skill` truncation branch and the `truncated` tool-result details. - Update tests and skill metadata mocks to reflect that large skills load in full. - Add a changeset for `@electric-ax/agents-runtime`. ## Key Invariants - `use_skill` inserts complete skill instructions into context. - Skill loading no longer reports a `truncated` flag or warning. - Oversized skills should be fixed at the skill-authoring level rather than partially loaded by the runtime. ## Non-goals - This does not change general context assembly/source-budget truncation behavior. - This does not add a replacement hard block for large skills. ## Trade-offs The previous `max` field acted as a hard per-skill safety cap, but it produced incomplete instructions. This PR removes that contract so legitimate skills are not silently corrupted; if a skill is too large, the skill itself should be split or improved. ## Verification ```bash cd packages/agents-runtime pnpm vitest run test/skills/tools.test.ts test/skills/preamble.test.ts cd ../.. pnpm --filter @electric-ax/agents-runtime typecheck GITHUB_BASE_REF=main node scripts/check-changeset.mjs ``` Results: - `test/skills/tools.test.ts` and `test/skills/preamble.test.ts`: 17 tests passed. - `@electric-ax/agents-runtime` typecheck passed. - Changeset validation passed for `@electric-ax/agents-runtime`. ## Files changed - `.changeset/remove-skill-content-max.md`: adds a patch changeset. - `packages/agents-runtime/src/skills/types.ts`: removes `SkillMeta.max`. - `packages/agents-runtime/src/skills/extract-meta.ts`: stops defaulting/extracting skill `max`. - `packages/agents-runtime/src/skills/preamble.ts`: stops parsing `max` from skill frontmatter. - `packages/agents-runtime/src/skills/tools.ts`: removes skill content truncation and `truncated` details. - `packages/agents-runtime/test/skills/*.test.ts`: updates tests and fixtures for full skill loading.
1 parent ee0da19 commit c14a886

8 files changed

Lines changed: 12 additions & 41 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@electric-ax/agents-runtime': patch
3+
---
4+
5+
Remove the skill content `max` cap so `use_skill` loads complete skill instructions instead of truncating them.

packages/agents-runtime/src/skills/extract-meta.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,8 @@ interface ExtractedMeta {
77
arguments?: Array<string>
88
argumentHint?: string
99
userInvocable?: boolean
10-
max: number
1110
}
1211

13-
const DEFAULT_MAX = 10_000
14-
1512
export async function extractSkillMeta(
1613
name: string,
1714
content: string
@@ -26,7 +23,6 @@ export async function extractSkillMeta(
2623
...(preamble.arguments && { arguments: preamble.arguments }),
2724
...(preamble.argumentHint && { argumentHint: preamble.argumentHint }),
2825
...(preamble.userInvocable && { userInvocable: true }),
29-
max: preamble.max ?? DEFAULT_MAX,
3026
}
3127
}
3228

@@ -35,7 +31,6 @@ export async function extractSkillMeta(
3531
whenToUse:
3632
preamble.whenToUse ?? `User asks about ${humanize(name).toLowerCase()}`,
3733
keywords: preamble.keywords ?? [name],
38-
max: preamble.max ?? DEFAULT_MAX,
3934
}
4035
}
4136

packages/agents-runtime/src/skills/preamble.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ export interface PreambleFields {
55
arguments?: Array<string>
66
argumentHint?: string
77
userInvocable?: boolean
8-
max?: number
98
}
109

1110
export function parsePreamble(content: string): PreambleFields {
@@ -82,11 +81,6 @@ export function parsePreamble(content: string): PreambleFields {
8281
case `user-invocable`:
8382
result.userInvocable = rawValue === `true`
8483
break
85-
case `max`: {
86-
const num = parseInt(rawValue, 10)
87-
if (!Number.isNaN(num) && num > 0) result.max = num
88-
break
89-
}
9084
}
9185
}
9286

packages/agents-runtime/src/skills/tools.ts

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ function skillContextId(name: string): string {
1212
export interface LoadSkillResult {
1313
loaded: boolean
1414
alreadyLoaded?: boolean
15-
truncated?: boolean
1615
chars?: number
1716
message: string
1817
contextSource?: string
@@ -50,12 +49,6 @@ export async function loadSkillIntoContext(
5049
}
5150
}
5251

53-
let truncated = false
54-
if (content.length > meta.max) {
55-
truncated = true
56-
content = content.slice(0, meta.max)
57-
}
58-
5952
if (args) {
6053
content = substituteArgs(content, args, meta.arguments)
6154
}
@@ -67,9 +60,6 @@ export async function loadSkillIntoContext(
6760
})
6861

6962
const skillDir = path.join(path.dirname(meta.source), name)
70-
const truncNote = truncated
71-
? `\n\nWARNING: Content was truncated from ${meta.charCount.toLocaleString()} to ${meta.max.toLocaleString()} chars. Inform the user.`
72-
: ``
7363

7464
const allRefFiles = listRefFiles(skillDir)
7565
const mdFiles = allRefFiles.filter((f) => f.endsWith(`.md`))
@@ -96,11 +86,10 @@ export async function loadSkillIntoContext(
9686
const dirNote = hasRefDir ? `\nSkill directory: ${skillDir}` : ``
9787
const refSection =
9888
refContents.length > 0 ? `\n\n${refContents.join(`\n\n`)}` : ``
99-
const contextSource = `SKILL ACTIVATED: "${name}". The instructions below override your default behavior. Follow them exactly. Do not read any files to find this content — it is all here.\n${dirNote}${truncNote}\n\n${content}${refSection}`
89+
const contextSource = `SKILL ACTIVATED: "${name}". The instructions below override your default behavior. Follow them exactly. Do not read any files to find this content — it is all here.\n${dirNote}\n\n${content}${refSection}`
10090

10191
return {
10292
loaded: true,
103-
truncated,
10493
chars: content.length,
10594
message: contextSource,
10695
contextSource,
@@ -136,7 +125,6 @@ export function createSkillTools(
136125
...(result.alreadyLoaded
137126
? { alreadyLoaded: result.alreadyLoaded }
138127
: {}),
139-
...(result.truncated ? { truncated: result.truncated } : {}),
140128
...(result.chars !== undefined ? { chars: result.chars } : {}),
141129
},
142130
}

packages/agents-runtime/src/skills/types.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ export interface SkillMeta {
66
arguments?: Array<string>
77
argumentHint?: string
88
userInvocable?: boolean
9-
max: number
109
charCount: number
1110
contentHash: string
1211
source: string

packages/agents-runtime/test/skills/context-loader.test.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ function createRegistry(): SkillsRegistry {
1717
whenToUse: `User wants a tutorial`,
1818
keywords: [`quickstart`],
1919
userInvocable: true,
20-
max: 1000,
2120
charCount: 100,
2221
contentHash: `hash-1`,
2322
source: `/skills/quickstart.md`,
@@ -33,7 +32,6 @@ function createRegistry(): SkillsRegistry {
3332
arguments: [`project_name`, `Bad-Arg`],
3433
argumentHint: `[project-name]`,
3534
userInvocable: true,
36-
max: 1000,
3735
charCount: 100,
3836
contentHash: `hash-2`,
3937
source: `/skills/init.md`,
@@ -47,7 +45,6 @@ function createRegistry(): SkillsRegistry {
4745
whenToUse: `Never directly`,
4846
keywords: [],
4947
userInvocable: false,
50-
max: 1000,
5148
charCount: 100,
5249
contentHash: `hash-3`,
5350
source: `/skills/internal.md`,
@@ -61,7 +58,6 @@ function createRegistry(): SkillsRegistry {
6158
whenToUse: `Never directly`,
6259
keywords: [],
6360
userInvocable: true,
64-
max: 1000,
6561
charCount: 100,
6662
contentHash: `hash-4`,
6763
source: `/skills/bad.md`,

packages/agents-runtime/test/skills/preamble.test.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ describe(`parsePreamble`, () => {
77
description: Interactive tutorial guide
88
whenToUse: User asks about tutorials or getting started
99
keywords: [tutorial, multi-agent, spawn]
10-
max: 15000
1110
---
1211
1312
# Tutorial content here`
@@ -17,7 +16,6 @@ max: 15000
1716
description: `Interactive tutorial guide`,
1817
whenToUse: `User asks about tutorials or getting started`,
1918
keywords: [`tutorial`, `multi-agent`, `spawn`],
20-
max: 15000,
2119
})
2220
})
2321

@@ -69,7 +67,6 @@ keywords:
6967
- getting started
7068
- learn
7169
- multi-agent
72-
max: 10000
7370
---
7471
7572
# Content here`
@@ -81,7 +78,6 @@ max: 10000
8178
`learn`,
8279
`multi-agent`,
8380
])
84-
expect(result.max).toBe(10000)
8581
})
8682

8783
it(`strips surrounding quotes from description and whenToUse`, () => {

packages/agents-runtime/test/skills/tools.test.ts

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ const QUICKSTART_META: SkillMeta = {
3939
description: `A quickstart`,
4040
whenToUse: `When learning`,
4141
keywords: [`quickstart`],
42-
max: 10_000,
4342
charCount: 500,
4443
contentHash: `abc123`,
4544
source: `/skills/quickstart.md`,
@@ -112,9 +111,9 @@ describe(`skill tools`, () => {
112111
})
113112
})
114113

115-
it(`use_skill truncates and warns when content exceeds max`, async () => {
114+
it(`use_skill loads full content for large skills`, async () => {
116115
const bigContent = `x`.repeat(15_000)
117-
const meta = { ...QUICKSTART_META, max: 10_000, charCount: 15_000 }
116+
const meta = { ...QUICKSTART_META, charCount: 15_000 }
118117
const registry = createMockRegistry({
119118
quickstart: { meta, content: bigContent },
120119
})
@@ -125,13 +124,12 @@ describe(`skill tools`, () => {
125124
const result = await useTool.execute(`tc1`, { name: `quickstart` })
126125

127126
const insertedContent = ctx.insertContext.mock.calls[0]![1].content
128-
// Content is truncated to max (10,000) — no wrapper prefix in insertContext
129-
expect(insertedContent).toContain(`x`.repeat(100))
130-
expect(insertedContent.length).toBe(10_000)
131-
// Tool result contains truncation warning
127+
expect(insertedContent).toBe(bigContent)
128+
expect(result.details).toMatchObject({ loaded: true, chars: 15_000 })
129+
expect(result.details).not.toHaveProperty(`truncated`)
132130
expect(result.content[0]).toMatchObject({
133131
type: `text`,
134-
text: expect.stringContaining(`truncated`),
132+
text: expect.not.stringContaining(`truncated`),
135133
})
136134
})
137135

0 commit comments

Comments
 (0)