@inixiative/agent-session 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +73 -0
- package/package.json +24 -0
- package/src/claude-code-session.ts +779 -0
- package/src/codex-session.ts +947 -0
- package/src/harness-session.ts +155 -0
- package/src/index.ts +21 -0
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// HarnessSession — provider-agnostic interface for long-lived agent sessions
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
//
|
|
5
|
+
// A HarnessSession wraps a live agent subprocess (Claude Code, Codex, Cursor)
|
|
6
|
+
// with bidirectional JSON streaming. One process startup per session, then
|
|
7
|
+
// messages flow as JSON lines over stdin/stdout.
|
|
8
|
+
//
|
|
9
|
+
// This is NOT an LLMProvider. LLMProvider is stateless (complete → result).
|
|
10
|
+
// HarnessSession is stateful: it owns a running process, tracks turns,
|
|
11
|
+
// captures every event for Oracle, and supports fork/interrupt.
|
|
12
|
+
//
|
|
13
|
+
// Implementations: ClaudeCodeSession (now), CodexSession / CursorSession (future)
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
// Event taxonomy — classified events from the agent stream
|
|
18
|
+
// ---------------------------------------------------------------------------
|
|
19
|
+
|
|
20
|
+
export type SessionEventKind =
|
|
21
|
+
| "session_start"
|
|
22
|
+
| "session_end"
|
|
23
|
+
| "session_compact"
|
|
24
|
+
| "text"
|
|
25
|
+
| "tool_use"
|
|
26
|
+
| "tool_result"
|
|
27
|
+
| "thinking"
|
|
28
|
+
| "result"
|
|
29
|
+
| "error";
|
|
30
|
+
|
|
31
|
+
export interface SessionEvent {
|
|
32
|
+
readonly kind: SessionEventKind;
|
|
33
|
+
readonly timestamp: number;
|
|
34
|
+
/** Text content (for text, thinking, result, error). */
|
|
35
|
+
readonly text?: string;
|
|
36
|
+
/** Tool name (for tool_use). */
|
|
37
|
+
readonly toolName?: string;
|
|
38
|
+
/** Tool input arguments (for tool_use). */
|
|
39
|
+
readonly toolInput?: Record<string, unknown>;
|
|
40
|
+
/** Tool output (for tool_result). */
|
|
41
|
+
readonly toolOutput?: string;
|
|
42
|
+
/** Whether the tool call failed (for tool_result). */
|
|
43
|
+
readonly toolError?: boolean;
|
|
44
|
+
/** Compaction source runtime (for session_compact): "claude-code" | "codex" | etc. */
|
|
45
|
+
readonly compactionSource?: string;
|
|
46
|
+
/**
|
|
47
|
+
* The agent runtime's native session ID (e.g. the UUID Claude Code uses
|
|
48
|
+
* as the filename in ~/.claude/projects/<id>.jsonl). External to Foundry —
|
|
49
|
+
* this is NOT the Foundry thread ID. A SessionAdapter maps between the two.
|
|
50
|
+
*/
|
|
51
|
+
readonly externalSessionId?: string;
|
|
52
|
+
/** Token usage (for result). */
|
|
53
|
+
readonly tokens?: { input: number; output: number };
|
|
54
|
+
/** Raw message from the stream (for Oracle introspection). */
|
|
55
|
+
readonly raw?: unknown;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** Result of a single send() — the turn's content plus all classified events. */
|
|
59
|
+
export interface SessionResult {
|
|
60
|
+
readonly content: string;
|
|
61
|
+
readonly events: readonly SessionEvent[];
|
|
62
|
+
readonly tokens?: { input: number; output: number };
|
|
63
|
+
/** The runtime's native session ID. See SessionEvent.externalSessionId. */
|
|
64
|
+
readonly externalSessionId?: string;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** Full session record for Oracle evaluation. */
|
|
68
|
+
export interface SessionArtifact {
|
|
69
|
+
/** The runtime's native session ID. See SessionEvent.externalSessionId. */
|
|
70
|
+
readonly externalSessionId?: string;
|
|
71
|
+
readonly events: readonly SessionEvent[];
|
|
72
|
+
readonly startedAt: number;
|
|
73
|
+
readonly endedAt?: number;
|
|
74
|
+
readonly turns: number;
|
|
75
|
+
readonly totalTokens: { input: number; output: number };
|
|
76
|
+
readonly toolCalls: number;
|
|
77
|
+
readonly toolResults: number;
|
|
78
|
+
readonly errors: number;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export type SessionEventHandler = (event: SessionEvent) => void;
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Pre-send hook — wraps or rewrites the outgoing message before it reaches
|
|
85
|
+
* the underlying runtime. Multiple handlers compose in registration order:
|
|
86
|
+
* each sees the previous handler's output. Returns the transformed message
|
|
87
|
+
* (or the same message unchanged).
|
|
88
|
+
*
|
|
89
|
+
* This is how FlowOrchestrator injects delta context per turn: the Librarian
|
|
90
|
+
* computes "what's new since the last injection," formats it as a prefix,
|
|
91
|
+
* and the composed message goes to send().
|
|
92
|
+
*/
|
|
93
|
+
export type BeforeSendHook = (
|
|
94
|
+
message: string,
|
|
95
|
+
) => string | Promise<string>;
|
|
96
|
+
|
|
97
|
+
// ---------------------------------------------------------------------------
|
|
98
|
+
// HarnessSession interface
|
|
99
|
+
// ---------------------------------------------------------------------------
|
|
100
|
+
|
|
101
|
+
export interface HarnessSession {
|
|
102
|
+
readonly alive: boolean;
|
|
103
|
+
/**
|
|
104
|
+
* The agent runtime's native session ID — external to Foundry.
|
|
105
|
+
* `undefined` until the runtime emits it (typically on the first turn's
|
|
106
|
+
* system init event). Use a SessionAdapter to map between a Foundry
|
|
107
|
+
* thread ID and this external ID.
|
|
108
|
+
*/
|
|
109
|
+
readonly externalSessionId: string | undefined;
|
|
110
|
+
readonly events: readonly SessionEvent[];
|
|
111
|
+
readonly turns: number;
|
|
112
|
+
readonly totalTokens: Readonly<{ input: number; output: number }>;
|
|
113
|
+
|
|
114
|
+
/** Spawn the underlying process. Must be called before send(). */
|
|
115
|
+
start(): Promise<void>;
|
|
116
|
+
|
|
117
|
+
/** Send a message. Queued if another turn is in-flight. */
|
|
118
|
+
send(message: string, opts?: { timeout?: number }): Promise<SessionResult>;
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Fork: create a new (unstarted) session branching from current state.
|
|
122
|
+
* Caller must call start() on the forked session.
|
|
123
|
+
*/
|
|
124
|
+
fork(opts?: { cwd?: string; baseContext?: string }): HarnessSession;
|
|
125
|
+
|
|
126
|
+
/** Interrupt the current in-flight turn (best-effort). */
|
|
127
|
+
interrupt(): void;
|
|
128
|
+
|
|
129
|
+
/** Kill the session process and reject any pending turns. */
|
|
130
|
+
kill(): void;
|
|
131
|
+
|
|
132
|
+
/** Subscribe to live events. Returns unsubscribe function. */
|
|
133
|
+
onEvent(handler: SessionEventHandler): () => void;
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Register a pre-send transform. Runs in registration order before the
|
|
137
|
+
* message is written to the runtime. Used for per-turn delta injection.
|
|
138
|
+
* Returns an unregister function.
|
|
139
|
+
*/
|
|
140
|
+
onBeforeSend(hook: BeforeSendHook): () => void;
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Mid-turn push: out-of-band signal injected into an in-flight turn.
|
|
144
|
+
* Used by guards and Herald to deliver urgent feedback. Best-effort —
|
|
145
|
+
* the underlying runtime may or may not honor the push.
|
|
146
|
+
*
|
|
147
|
+
* Implementations that cannot support mid-turn push should emit a
|
|
148
|
+
* "push_ignored" error event rather than throw, so callers can observe
|
|
149
|
+
* that the push was attempted but not delivered.
|
|
150
|
+
*/
|
|
151
|
+
push(payload: { kind: string; text: string }): Promise<void>;
|
|
152
|
+
|
|
153
|
+
/** Full session record for Oracle evaluation. */
|
|
154
|
+
artifact(): SessionArtifact;
|
|
155
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// @inixiative/agent-session — drive coding-agent CLIs as persistent,
|
|
2
|
+
// streaming, event-captured sessions.
|
|
3
|
+
|
|
4
|
+
// The provider-agnostic interface + event taxonomy.
|
|
5
|
+
export * from "./harness-session";
|
|
6
|
+
|
|
7
|
+
// Claude Code adapter (persistent stream-json session, subscription auth).
|
|
8
|
+
export {
|
|
9
|
+
ClaudeCodeSession,
|
|
10
|
+
type ClaudeCodeSessionConfig,
|
|
11
|
+
} from "./claude-code-session";
|
|
12
|
+
|
|
13
|
+
// Codex CLI adapter (persistent JSON-RPC session). CodexSession defaults to the
|
|
14
|
+
// mcp-server variant; CodexAppServerSession is the experimental app-server one.
|
|
15
|
+
export {
|
|
16
|
+
CodexSession,
|
|
17
|
+
CodexMcpSession,
|
|
18
|
+
CodexAppServerSession,
|
|
19
|
+
type CodexSessionConfig,
|
|
20
|
+
type CodexSpawn,
|
|
21
|
+
} from "./codex-session";
|