feat(coding-agent): add ExtensionAPI setLabel

This commit is contained in:
Mario Zechner 2026-01-17 21:18:44 +01:00
parent fde9b089f4
commit 157e4e51bf
10 changed files with 41 additions and 0 deletions

View file

@ -4,6 +4,7 @@
### Added
- `pi.setLabel(entryId, label)` in ExtensionAPI for setting per-entry labels from extensions ([#806](https://github.com/badlogic/pi-mono/issues/806))
- Export `keyHint`, `appKeyHint`, `editorKey`, `appKey`, `rawKeyHint` for extensions to format keybinding hints consistently
- Added `showHardwareCursor` setting to control cursor visibility while still positioning it for IME support. ([#800](https://github.com/badlogic/pi-mono/pull/800) by [@ghoulr](https://github.com/ghoulr))
- Added `ctx.compact()` and `ctx.getContextUsage()` to extension contexts for programmatic compaction and context usage checks.

View file

@ -904,6 +904,23 @@ if (name) {
}
```
### pi.setLabel(entryId, label)
Set or clear a label on an entry. Labels are user-defined markers for bookmarking and navigation (shown in `/tree` selector).
```typescript
// Set a label
pi.setLabel(entryId, "checkpoint-before-refactor");
// Clear a label
pi.setLabel(entryId, undefined);
// Read labels via sessionManager
const label = ctx.sessionManager.getLabel(entryId);
```
Labels persist in the session and survive restarts. Use them to mark important points (turns, checkpoints) in the conversation tree.
### pi.registerCommand(name, options)
Register a command.

View file

@ -98,6 +98,7 @@ export type {
SessionSwitchEvent,
SessionTreeEvent,
SetActiveToolsHandler,
SetLabelHandler,
SetModelHandler,
SetThinkingLevelHandler,
// Events - Tool

View file

@ -114,6 +114,7 @@ export function createExtensionRuntime(): ExtensionRuntime {
appendEntry: notInitialized,
setSessionName: notInitialized,
getSessionName: notInitialized,
setLabel: notInitialized,
getActiveTools: notInitialized,
getAllTools: notInitialized,
setActiveTools: notInitialized,
@ -205,6 +206,10 @@ function createExtensionAPI(
return runtime.getSessionName();
},
setLabel(entryId: string, label: string | undefined): void {
runtime.setLabel(entryId, label);
},
exec(command: string, args: string[], options?: ExecOptions) {
return execCommand(command, args, options?.cwd ?? cwd, options);
},

View file

@ -149,6 +149,7 @@ export class ExtensionRunner {
this.runtime.appendEntry = actions.appendEntry;
this.runtime.setSessionName = actions.setSessionName;
this.runtime.getSessionName = actions.getSessionName;
this.runtime.setLabel = actions.setLabel;
this.runtime.getActiveTools = actions.getActiveTools;
this.runtime.getAllTools = actions.getAllTools;
this.runtime.setActiveTools = actions.setActiveTools;

View file

@ -813,6 +813,9 @@ export interface ExtensionAPI {
/** Get the current session name, if set. */
getSessionName(): string | undefined;
/** Set or clear a label on an entry. Labels are user-defined markers for bookmarking/navigation. */
setLabel(entryId: string, label: string | undefined): void;
/** Execute a shell command. */
exec(command: string, args: string[], options?: ExecOptions): Promise<ExecResult>;
@ -902,6 +905,8 @@ export type GetThinkingLevelHandler = () => ThinkingLevel;
export type SetThinkingLevelHandler = (level: ThinkingLevel) => void;
export type SetLabelHandler = (entryId: string, label: string | undefined) => void;
/**
* Shared state created by loader, used during registration and runtime.
* Contains flag values (defaults set during registration, CLI values set after).
@ -920,6 +925,7 @@ export interface ExtensionActions {
appendEntry: AppendEntryHandler;
setSessionName: SetSessionNameHandler;
getSessionName: GetSessionNameHandler;
setLabel: SetLabelHandler;
getActiveTools: GetActiveToolsHandler;
getAllTools: GetAllToolsHandler;
setActiveTools: SetActiveToolsHandler;

View file

@ -669,6 +669,9 @@ export class InteractiveMode {
getSessionName: () => {
return this.sessionManager.getSessionName();
},
setLabel: (entryId, label) => {
this.sessionManager.appendLabelChange(entryId, label);
},
getActiveTools: () => this.session.getActiveToolNames(),
getAllTools: () => this.session.getAllTools(),
setActiveTools: (toolNames) => this.session.setActiveToolsByName(toolNames),

View file

@ -60,6 +60,9 @@ export async function runPrintMode(session: AgentSession, options: PrintModeOpti
getSessionName: () => {
return session.sessionManager.getSessionName();
},
setLabel: (entryId, label) => {
session.sessionManager.appendLabelChange(entryId, label);
},
getActiveTools: () => session.getActiveToolNames(),
getAllTools: () => session.getAllTools(),
setActiveTools: (toolNames: string[]) => session.setActiveToolsByName(toolNames),

View file

@ -273,6 +273,9 @@ export async function runRpcMode(session: AgentSession): Promise<never> {
getSessionName: () => {
return session.sessionManager.getSessionName();
},
setLabel: (entryId, label) => {
session.sessionManager.appendLabelChange(entryId, label);
},
getActiveTools: () => session.getActiveToolNames(),
getAllTools: () => session.getAllTools(),
setActiveTools: (toolNames: string[]) => session.setActiveToolsByName(toolNames),

View file

@ -110,6 +110,7 @@ describe.skipIf(!API_KEY)("Compaction extensions", () => {
appendEntry: async () => {},
setSessionName: () => {},
getSessionName: () => undefined,
setLabel: () => {},
getActiveTools: () => [],
getAllTools: () => [],
setActiveTools: () => {},