Skip to content

Commit c12cdb4

Browse files
fix(agent): corrected read-before-write prompt, install_skill capture-and-continue (#816)
Co-authored-by: Edwin Lim <edwin@posthog.com>
1 parent 16759b2 commit c12cdb4

6 files changed

Lines changed: 75 additions & 1 deletion

File tree

src/lib/agent/__tests__/output-signals.test.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,4 +129,32 @@ describe('AgentOutputSignals', () => {
129129
expect(signals.usedManagedLogin()).toBe(true);
130130
});
131131
});
132+
133+
describe('skillInstallFailure', () => {
134+
it('returns the detail after the marker', () => {
135+
const signals = new AgentOutputSignals();
136+
signals.push('some prose');
137+
signals.push(
138+
'[SKILL-INSTALL-FAILED] integration-nextjs-app-router — download timed out',
139+
);
140+
141+
expect(signals.skillInstallFailure()).toBe(
142+
'integration-nextjs-app-router — download timed out',
143+
);
144+
});
145+
146+
it("reports '' for a bare marker so the failure is never lost", () => {
147+
const signals = new AgentOutputSignals();
148+
signals.push('[SKILL-INSTALL-FAILED]');
149+
150+
expect(signals.skillInstallFailure()).toBe('');
151+
});
152+
153+
it('is undefined when the skill installed fine', () => {
154+
const signals = new AgentOutputSignals();
155+
signals.push('[STATUS] Installing skill');
156+
157+
expect(signals.skillInstallFailure()).toBeUndefined();
158+
});
159+
});
132160
});

src/lib/agent/agent-interface.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -858,6 +858,15 @@ export async function runAgent(
858858
analytics.capture(WIZARD_REMARK_EVENT_NAME, { remark });
859859
}
860860

861+
// A failed install_skill is non-fatal — the agent continues best-effort
862+
// without the skill — but every such run must be measurable.
863+
const skillFailure = signals.skillInstallFailure();
864+
if (skillFailure !== undefined) {
865+
analytics.wizardCapture('agent continued without skill', {
866+
detail: skillFailure,
867+
});
868+
}
869+
861870
// Token usage comes from the SDK result message and is per agent run —
862871
// for the orchestrator that means per task, the secondary cost to watch.
863872
const usage = lastResultMessage?.usage as

src/lib/agent/output-signals.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ const OUTPUT_SIGNALS = {
2525
API_ERROR: 'API Error:',
2626
MCP_MISSING: AgentSignals.ERROR_MCP_MISSING,
2727
RESOURCE_MISSING: AgentSignals.ERROR_RESOURCE_MISSING,
28+
SKILL_INSTALL_FAILED: AgentSignals.SKILL_INSTALL_FAILED,
2829
WIZARD_REMARK: AgentSignals.WIZARD_REMARK,
2930
} as const;
3031

@@ -89,6 +90,20 @@ export class AgentOutputSignals {
8990
return m ? m.join('\n') : undefined;
9091
}
9192

93+
/**
94+
* Text after the `[SKILL-INSTALL-FAILED]` marker (skill id + reason),
95+
* trimmed — or undefined when the skill installed fine. A marker with no
96+
* trailing text still reports as '' so the failure is never lost.
97+
*/
98+
skillInstallFailure(): string | undefined {
99+
const marker = OUTPUT_SIGNALS.SKILL_INSTALL_FAILED;
100+
for (const line of this.lines) {
101+
const idx = line.indexOf(marker);
102+
if (idx !== -1) return line.slice(idx + marker.length).trim();
103+
}
104+
return undefined;
105+
}
106+
92107
/** Text after the single `[WIZARD-REMARK]` marker, trimmed, or undefined. */
93108
remark(): string | undefined {
94109
const re = new RegExp(

src/lib/agent/runner/harness/pi/index.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -566,6 +566,15 @@ export const piBackend: AgentHarness = {
566566
analytics.capture(WIZARD_REMARK_EVENT_NAME, { remark });
567567
}
568568

569+
// A failed install_skill is non-fatal — the agent continues best-effort
570+
// without the skill — but every such run must be measurable.
571+
const skillFailure = signals.skillInstallFailure();
572+
if (skillFailure !== undefined) {
573+
analytics.wizardCapture('agent continued without skill', {
574+
detail: skillFailure,
575+
});
576+
}
577+
569578
// The skill plans events into .posthog-events.json then asks to remove it
570579
// on completion; pi's `rm` is fence-blocked, so the agent can't — clean it
571580
// up host-side rather than leave a stale (often empty) artifact (#15).

src/lib/agent/signals.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,14 @@ export const AgentSignals = {
1111
ERROR_MCP_MISSING: '[ERROR-MCP-MISSING]',
1212
/** Signal emitted when the agent cannot access the setup resource */
1313
ERROR_RESOURCE_MISSING: '[ERROR-RESOURCE-MISSING]',
14+
/**
15+
* Signal emitted when `install_skill` failed and the agent is continuing
16+
* the integration WITHOUT the skill (best-effort from its own knowledge).
17+
* Format: "[SKILL-INSTALL-FAILED] <skill id — reason>". Non-fatal by
18+
* design: a freestyled integration beats an outright failure, but the run
19+
* must be measurable — the runner captures it as an analytics event.
20+
*/
21+
SKILL_INSTALL_FAILED: '[SKILL-INSTALL-FAILED]',
1422
/**
1523
* Signal emitted when the agent cannot complete the program and is
1624
* aborting intentionally (distinct from errors). Format: "[ABORT] <reason>".

src/lib/programs/posthog-integration/index.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,11 @@ STEP 1: Call load_skill_menu (from the wizard-tools MCP server) to see available
188188
189189
STEP 2: Call install_skill (from the wizard-tools MCP server) with the chosen skill ID (e.g., "integration-nextjs-app-router").
190190
Do NOT run any shell commands to install skills.
191+
If install_skill fails, emit on its own line: ${
192+
AgentSignals.SKILL_INSTALL_FAILED
193+
} <skill id — one-line reason>. Then CONTINUE and SKIP to STEP 5 the integration without the skill, following these steps and your knowledge of ${
194+
config.metadata.name
195+
} and PostHog's official docs, and note in the setup report that the skill could not be installed.
191196
192197
STEP 3: Load the installed skill's SKILL.md file to understand what references are available.
193198
@@ -200,7 +205,7 @@ STEP 5: Set up environment variables for PostHog using the wizard-tools MCP serv
200205
}, which you'll find in example code. The tool will also ensure .gitignore coverage. Don't assume the presence of keys means the value is up to date. Write the correct value each time.
201206
- Reference these environment variables in the code files you create instead of hardcoding the public token and host.
202207
203-
Important: Use the detect_package_manager tool (from the wizard-tools MCP server) to determine which package manager the project uses, then run its install command to add the SDK. Do not manually search for lockfiles or config files. You must read a file immediately before attempting to write it, even if you have previously read it; failure to do so will cause a tool failure.
208+
Important: Use the detect_package_manager tool (from the wizard-tools MCP server) to determine which package manager the project uses, then run its install command to add the SDK. Do not manually search for lockfiles or config files. If a file already EXISTS, read it immediately before you edit or overwrite it — writing from a stale read causes a tool failure. Creating a brand-new file needs no prior read: never read a path that does not exist yet; just write it.
204209
205210
206211
`;

0 commit comments

Comments
 (0)