earendil-works/pi · error · HarnessNotImplemented

AgentHarness.create.restore is not implemented yet

Error message

AgentHarness.create.restore is not implemented yet

What it means

AgentHarness.create() builds a harness over a SessionTree, but restoring an existing session is not implemented yet: if options.session.findRecords({ limit: 1 }) returns any record, create rejects with HarnessNotImplemented('create.restore') instead of resuming. The harness is a work-in-progress surface where most operations similarly reject with HarnessNotImplemented, so create only succeeds on a fresh, empty session. The error class carries an `operation` field ('create.restore') for precise handling.

Source

Thrown at packages/agent/src/harness/agent-harness.ts:351

			skills: options.resources?.skills ? [...options.resources.skills] : undefined,
			promptTemplates: options.resources?.promptTemplates ? [...options.resources.promptTemplates] : undefined,
		};
		this.streamOptions = { ...(options.streamOptions ?? {}) };
		this.retryPolicy = options.retry ?? { enabled: false, maxRetries: 0, baseDelayMs: 1000 };
		this.compactionSettings = options.compaction ?? {
			enabled: true,
			reserveTokens: 16384,
			keepRecentTokens: 20000,
		};
		this.steeringMode = options.steeringMode ?? "one-at-a-time";
		this.followUpMode = options.followUpMode ?? "one-at-a-time";
	}

	static async create(
		options: AgentHarnessOptions,
	): Promise<{ harness: AgentHarness; suspended: SuspendedOperation[] }> {
		const [record] = await options.session.findRecords({ limit: 1 });
		if (record !== undefined) throw new HarnessNotImplemented("create.restore");
		return { harness: new AgentHarness(options), suspended: [] };
	}

	private unavailable<T>(operation: string): Promise<T> {
		return Promise.reject(this.closed ? new HarnessClosed() : new HarnessNotImplemented(operation));
	}

	async getLeafId(): Promise<string | null> {
		return this.durableSession.getLeafId();
	}

	async prompt(_text: string, _images?: ImageContent[]): Promise<RunResult>;
	async prompt(_message: AgentMessage | AgentMessage[]): Promise<RunResult>;
	async prompt(_input: string | AgentMessage | AgentMessage[], _images?: ImageContent[]): Promise<RunResult> {
		return this.unavailable("prompt");
	}
	async skill(_name: string, _additionalInstructions?: string): Promise<RunResult> {
		return this.unavailable("skill");

View on GitHub (pinned to 4af9d21d3b)

Solutions

  1. Pass a brand-new, empty Session/SessionTree so findRecords returns nothing.
  2. Pre-check options.session.findRecords({ limit: 1 }) yourself and fail with your own error before calling create.
  3. Until create.restore ships, use the Agent class directly for resumable conversations and treat the harness as experimental (its prompt/steer/watch/etc. also reject with HarnessNotImplemented).

Example fix

// before
const { harness } = await AgentHarness.create({ session: existingSession }); // has records -> HarnessNotImplemented

// after
const [record] = await existingSession.findRecords({ limit: 1 });
if (record !== undefined) throw new Error("session restore not supported by this harness version");
const { harness } = await AgentHarness.create({ session: freshEmptySession });
Defensive patterns

Strategy: try-catch

Validate before calling

const [record] = await options.session.findRecords({ limit: 1 });
if (record !== undefined) {
  // restore is unimplemented: use a fresh session instead
  throw new Error("session has records; harness restore not implemented");
}
const { harness } = await AgentHarness.create(options);

Type guard

function isHarnessNotImplemented(err: unknown, operation?: string): err is HarnessNotImplemented {
  return err instanceof HarnessNotImplemented && (operation === undefined || err.operation === operation);
}

Try / catch

try {
  const { harness, suspended } = await AgentHarness.create(options);
} catch (err) {
  if (err instanceof HarnessNotImplemented && err.operation === "create.restore") {
    // fall back: create a fresh session, or use the Agent class directly
  } else {
    throw err;
  }
}

Prevention

When it happens

Trigger: Passing a durable Session that already contains records (a previously used or persisted session tree) to AgentHarness.create(); reopening a session store on app restart and expecting resume; pointing AgentHarnessOptions.session at a shared or populated store.

Common situations: Apps that persist sessions and call create() on every startup; test fixtures reusing a session directory; upgrading to a harness version where restore simply has not shipped yet.


AI-assisted analysis of earendil-works/pi@4af9d21d3b (2026-08-24). Data as JSON: /api/errors/d127645b915994c3. Report an issue: GitHub.