@shareai-lab/kode-sdk 1.0.0-beta.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.
@@ -0,0 +1,687 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Agent = void 0;
4
+ const events_1 = require("./events");
5
+ const hooks_1 = require("./hooks");
6
+ const scheduler_1 = require("./scheduler");
7
+ class Agent {
8
+ constructor(templateOrOpts, overrides) {
9
+ this.tools = new Map();
10
+ this.messages = [];
11
+ this.state = 'READY';
12
+ this.lastSfpIndex = -1;
13
+ this.stepCount = 0;
14
+ this.events = new events_1.EventBus();
15
+ this.hooks = new hooks_1.HookManager();
16
+ this.pendingPermissions = new Map();
17
+ this.interrupted = false;
18
+ let opts;
19
+ if ('sessionId' in templateOrOpts) {
20
+ opts = templateOrOpts;
21
+ }
22
+ else {
23
+ if (!overrides)
24
+ throw new Error('overrides required when using template');
25
+ opts = {
26
+ sessionId: overrides.sessionId,
27
+ provider: overrides.provider,
28
+ store: overrides.store,
29
+ sandbox: overrides.sandbox,
30
+ tools: templateOrOpts.tools || [],
31
+ system: templateOrOpts.system,
32
+ templateId: templateOrOpts.id,
33
+ ...overrides,
34
+ };
35
+ }
36
+ this.sessionId = opts.sessionId;
37
+ this.provider = opts.provider;
38
+ this.store = opts.store;
39
+ this.sandbox = opts.sandbox;
40
+ this.system = opts.system;
41
+ this.maxTokens = opts.maxTokens || 4096;
42
+ this.temperature = opts.temperature ?? 0.7;
43
+ this.maxConcurrency = opts.maxConcurrency || 3;
44
+ this.templateId = opts.templateId || 'default';
45
+ // Connect EventBus to Store for event persistence
46
+ this.events.setStore(this.store, this.sessionId);
47
+ if (opts.tools) {
48
+ for (const tool of opts.tools) {
49
+ this.tools.set(tool.name, tool);
50
+ if (tool.hooks) {
51
+ this.hooks.register(tool.hooks);
52
+ }
53
+ }
54
+ }
55
+ }
56
+ async send(text) {
57
+ const messageId = `msg-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
58
+ this.messages.push({
59
+ role: 'user',
60
+ content: [{ type: 'text', text }],
61
+ });
62
+ this.stepCount++;
63
+ await this.persistMessages();
64
+ this.events.emitEvent({
65
+ type: 'messages_update',
66
+ messageCount: this.messages.length,
67
+ lastSfpIndex: this.lastSfpIndex,
68
+ added: 1,
69
+ });
70
+ // Start processing in background (non-blocking)
71
+ this.step().catch((err) => {
72
+ this.events.emitEvent({
73
+ type: 'error',
74
+ kind: 'ProviderError',
75
+ message: err.message,
76
+ hint: err.stack,
77
+ });
78
+ });
79
+ return messageId;
80
+ }
81
+ subscribe(opts) {
82
+ return this.events.subscribe(opts);
83
+ }
84
+ async *chat(text) {
85
+ const since = this.events.getCursor();
86
+ await this.send(text);
87
+ for await (const event of this.subscribe({ since })) {
88
+ yield event;
89
+ if (event.type === 'state' && event.state === 'READY')
90
+ break;
91
+ }
92
+ }
93
+ async reply(text) {
94
+ let fullText = '';
95
+ for await (const event of this.chat(text)) {
96
+ if (event.type === 'text') {
97
+ fullText = event.text;
98
+ }
99
+ }
100
+ return fullText;
101
+ }
102
+ async askLLM(text, opts) {
103
+ const provider = opts?.provider || this.provider;
104
+ const messages = [{ role: 'user', content: [{ type: 'text', text }] }];
105
+ const response = await provider.complete(messages, {
106
+ tools: opts?.useTools ? this.getToolSchemas() : undefined,
107
+ system: opts?.system || this.system,
108
+ maxTokens: this.maxTokens,
109
+ temperature: this.temperature,
110
+ });
111
+ const textBlock = response.content.find((c) => c.type === 'text');
112
+ return {
113
+ text: textBlock ? textBlock.text : '',
114
+ sessionId: opts?.sessionId || this.sessionId,
115
+ };
116
+ }
117
+ async interrupt(opts) {
118
+ this.interrupted = true;
119
+ // Find pending tool_use blocks that haven't received results yet
120
+ const lastMsg = this.messages[this.messages.length - 1];
121
+ if (lastMsg?.role === 'assistant') {
122
+ const toolUses = lastMsg.content.filter(c => c.type === 'tool_use');
123
+ if (toolUses.length > 0) {
124
+ // Collect all existing tool_result IDs
125
+ const resultIds = new Set();
126
+ for (const msg of this.messages) {
127
+ for (const block of msg.content) {
128
+ if (block.type === 'tool_result') {
129
+ resultIds.add(block.tool_use_id);
130
+ }
131
+ }
132
+ }
133
+ // Generate cancelled results for pending tools
134
+ const cancelledResults = [];
135
+ for (const tu of toolUses) {
136
+ if (!resultIds.has(tu.id)) {
137
+ cancelledResults.push({
138
+ type: 'tool_result',
139
+ tool_use_id: tu.id,
140
+ content: { error: opts?.note || 'Interrupted by user' },
141
+ is_error: true,
142
+ });
143
+ this.events.emitEvent({
144
+ type: 'tool_result',
145
+ id: tu.id,
146
+ name: tu.name,
147
+ ok: false,
148
+ content: { error: opts?.note || 'Interrupted by user' },
149
+ });
150
+ }
151
+ }
152
+ // Add cancelled results to message history
153
+ if (cancelledResults.length > 0) {
154
+ this.messages.push({
155
+ role: 'user',
156
+ content: cancelledResults,
157
+ });
158
+ this.stepCount++;
159
+ this.lastSfpIndex = this.messages.length - 1;
160
+ await this.persistMessages();
161
+ this.events.emitEvent({
162
+ type: 'messages_update',
163
+ messageCount: this.messages.length,
164
+ lastSfpIndex: this.lastSfpIndex,
165
+ added: 1,
166
+ });
167
+ this.events.emitEvent({
168
+ type: 'commit',
169
+ sfpIndex: this.lastSfpIndex,
170
+ });
171
+ }
172
+ }
173
+ }
174
+ this.state = 'READY';
175
+ this.events.emitEvent({ type: 'state', state: 'READY' });
176
+ // Note is only for events/audit, not written to message stream
177
+ if (opts?.note) {
178
+ this.events.emitEvent({
179
+ type: 'error',
180
+ kind: 'PolicyViolation',
181
+ message: `Interrupted: ${opts.note}`,
182
+ });
183
+ }
184
+ }
185
+ async decide(permId, decision, note) {
186
+ const resolver = this.pendingPermissions.get(permId);
187
+ if (!resolver) {
188
+ throw new Error(`Permission not found: ${permId}`);
189
+ }
190
+ resolver(decision, note);
191
+ this.pendingPermissions.delete(permId);
192
+ this.events.emitEvent({ type: 'permission_decision', id: permId, decision, by: 'api' });
193
+ if (decision === 'allow') {
194
+ this.state = 'BUSY';
195
+ this.step().catch((err) => {
196
+ this.events.emitEvent({
197
+ type: 'error',
198
+ kind: 'ProviderError',
199
+ message: err.message,
200
+ });
201
+ });
202
+ }
203
+ }
204
+ async snapshot(label) {
205
+ const id = label || `sfp:${this.lastSfpIndex}`;
206
+ const snapshot = {
207
+ id,
208
+ messages: JSON.parse(JSON.stringify(this.messages)),
209
+ lastSfpIndex: this.lastSfpIndex,
210
+ createdAt: new Date().toISOString(),
211
+ };
212
+ await this.store.saveSnapshot(this.sessionId, snapshot);
213
+ return id;
214
+ }
215
+ async fork(sel) {
216
+ // 1. Load snapshot (or use current state if no selector)
217
+ let snapshot;
218
+ if (!sel) {
219
+ // Fork from current state
220
+ snapshot = {
221
+ id: `sfp:${this.lastSfpIndex}`,
222
+ messages: JSON.parse(JSON.stringify(this.messages)),
223
+ lastSfpIndex: this.lastSfpIndex,
224
+ createdAt: new Date().toISOString(),
225
+ };
226
+ }
227
+ else if (typeof sel === 'string') {
228
+ // Load snapshot by ID
229
+ const loaded = await this.store.loadSnapshot(this.sessionId, sel);
230
+ if (!loaded) {
231
+ throw new Error(`Snapshot not found: ${sel}`);
232
+ }
233
+ snapshot = loaded;
234
+ }
235
+ else {
236
+ // Load snapshot by selector
237
+ const snapshotId = sel.at || `sfp:${this.lastSfpIndex}`;
238
+ const loaded = await this.store.loadSnapshot(this.sessionId, snapshotId);
239
+ if (!loaded) {
240
+ throw new Error(`Snapshot not found: ${snapshotId}`);
241
+ }
242
+ snapshot = loaded;
243
+ }
244
+ // 2. Generate new sessionId for forked agent
245
+ const forkId = `fork:${Date.now()}`;
246
+ const newSessionId = `${this.sessionId}/${forkId}`;
247
+ // 3. Create new agent with same configuration
248
+ const forked = new Agent({
249
+ sessionId: newSessionId,
250
+ provider: this.provider,
251
+ store: this.store,
252
+ sandbox: this.sandbox,
253
+ tools: Array.from(this.tools.values()),
254
+ system: this.system,
255
+ maxTokens: this.maxTokens,
256
+ temperature: this.temperature,
257
+ maxConcurrency: this.maxConcurrency,
258
+ templateId: this.templateId,
259
+ });
260
+ // 4. Restore messages from snapshot
261
+ forked.messages = snapshot.messages;
262
+ forked.lastSfpIndex = snapshot.lastSfpIndex;
263
+ forked.stepCount = snapshot.messages.filter(m => m.role === 'user').length;
264
+ // 5. Persist forked state
265
+ await forked.persistMessages();
266
+ // 6. Emit forked event
267
+ this.events.emitEvent({
268
+ type: 'forked',
269
+ childSessionId: newSessionId,
270
+ from: snapshot.id,
271
+ });
272
+ return forked;
273
+ }
274
+ static async resume(sessionId, opts) {
275
+ const { autoRun = false, strategy = 'manual', store, ...agentOpts } = opts;
276
+ // Load messages from store
277
+ const messages = await store.loadMessages(sessionId);
278
+ if (messages.length === 0) {
279
+ throw new Error(`Session has no messages: ${sessionId}`);
280
+ }
281
+ // Create agent instance
282
+ const agent = new Agent({
283
+ ...agentOpts,
284
+ sessionId,
285
+ store,
286
+ });
287
+ // Restore messages
288
+ agent.messages = messages;
289
+ // Find last SFP
290
+ agent.lastSfpIndex = agent.findLastSfp();
291
+ // Restore step count
292
+ agent.stepCount = messages.filter((m) => m.role === 'user').length;
293
+ // Handle crash recovery: generate sealed results for pending tools
294
+ if (strategy === 'crash') {
295
+ const sealedTools = agent.findSealedTools();
296
+ if (sealedTools.length > 0) {
297
+ const sealedResults = sealedTools.map((tool) => ({
298
+ type: 'tool_result',
299
+ tool_use_id: tool.tool_use_id,
300
+ content: {
301
+ error: `Sealed due to crash: ${tool.note}`,
302
+ sealed: true,
303
+ },
304
+ is_error: true,
305
+ }));
306
+ agent.messages.push({
307
+ role: 'user',
308
+ content: sealedResults,
309
+ });
310
+ agent.stepCount++;
311
+ agent.lastSfpIndex = agent.messages.length - 1;
312
+ await agent.persistMessages();
313
+ agent.events.emitEvent({
314
+ type: 'resume',
315
+ from: 'crash',
316
+ sealed: sealedTools,
317
+ });
318
+ }
319
+ }
320
+ else {
321
+ agent.events.emitEvent({
322
+ type: 'resume',
323
+ from: 'manual',
324
+ sealed: [],
325
+ });
326
+ }
327
+ // AutoRun: continue execution if there are pending tools
328
+ if (autoRun) {
329
+ const lastMessage = messages[messages.length - 1];
330
+ if (lastMessage.role === 'assistant') {
331
+ const pendingTools = lastMessage.content.filter((c) => c.type === 'tool_use');
332
+ if (pendingTools.length > 0) {
333
+ agent.step().catch((err) => {
334
+ agent.events.emitEvent({
335
+ type: 'error',
336
+ kind: 'ProviderError',
337
+ message: err.message,
338
+ });
339
+ });
340
+ }
341
+ }
342
+ }
343
+ agent.state = 'READY';
344
+ agent.events.emitEvent({ type: 'state', state: 'READY' });
345
+ return agent;
346
+ }
347
+ findLastSfp() {
348
+ for (let i = this.messages.length - 1; i >= 0; i--) {
349
+ const msg = this.messages[i];
350
+ // User message is SFP
351
+ if (msg.role === 'user') {
352
+ return i;
353
+ }
354
+ // Assistant text-only message is SFP
355
+ if (msg.role === 'assistant') {
356
+ const hasToolUse = msg.content.some((c) => c.type === 'tool_use');
357
+ if (!hasToolUse) {
358
+ return i;
359
+ }
360
+ }
361
+ }
362
+ return -1;
363
+ }
364
+ findSealedTools() {
365
+ const sealed = [];
366
+ const toolUseMap = new Map();
367
+ const toolResultSet = new Set();
368
+ // Collect all tool_use and tool_result
369
+ for (const msg of this.messages) {
370
+ for (const block of msg.content) {
371
+ if (block.type === 'tool_use') {
372
+ const tu = block;
373
+ toolUseMap.set(tu.id, { name: tu.name, args: tu.input });
374
+ }
375
+ else if (block.type === 'tool_result') {
376
+ const tr = block;
377
+ toolResultSet.add(tr.tool_use_id);
378
+ }
379
+ }
380
+ }
381
+ // Find tool_use without results
382
+ for (const [toolId, tool] of toolUseMap.entries()) {
383
+ if (!toolResultSet.has(toolId)) {
384
+ sealed.push({
385
+ tool_use_id: toolId,
386
+ name: tool.name,
387
+ args: tool.args,
388
+ note: 'No result found, likely crashed during execution',
389
+ });
390
+ }
391
+ }
392
+ return sealed;
393
+ }
394
+ async history(opts) {
395
+ const timeline = this.events.getTimeline(opts?.since);
396
+ const limited = opts?.limit ? timeline.slice(0, opts.limit) : timeline;
397
+ return limited.map((t) => t.event);
398
+ }
399
+ async status() {
400
+ return {
401
+ state: this.state,
402
+ sessionId: this.sessionId,
403
+ messageCount: this.messages.length,
404
+ lastSfpIndex: this.lastSfpIndex,
405
+ cursor: this.events.getCursor(),
406
+ };
407
+ }
408
+ async info() {
409
+ return {
410
+ sessionId: this.sessionId,
411
+ templateId: this.templateId,
412
+ createdAt: new Date().toISOString(),
413
+ lineage: [],
414
+ messageCount: this.messages.length,
415
+ lastSfpIndex: this.lastSfpIndex,
416
+ };
417
+ }
418
+ use(hooks) {
419
+ this.hooks.register(hooks, 'agent');
420
+ return this;
421
+ }
422
+ getHooks() {
423
+ return this.hooks.getRegistered();
424
+ }
425
+ registerTools(tools) {
426
+ for (const tool of tools) {
427
+ this.tools.set(tool.name, tool);
428
+ if (tool.hooks) {
429
+ this.hooks.register(tool.hooks, 'toolTune');
430
+ }
431
+ }
432
+ return this;
433
+ }
434
+ schedule() {
435
+ if (!this.scheduler) {
436
+ this.scheduler = new scheduler_1.Scheduler();
437
+ // Connect step events to scheduler
438
+ this.on('messages_update', (event) => {
439
+ if (event.added && event.added > 0) {
440
+ this.scheduler.notifyStep();
441
+ }
442
+ });
443
+ }
444
+ return this.scheduler;
445
+ }
446
+ on(event, handler) {
447
+ this.events.on(event, handler);
448
+ return this;
449
+ }
450
+ async step() {
451
+ if (this.state !== 'READY')
452
+ return;
453
+ if (this.interrupted) {
454
+ this.interrupted = false;
455
+ return;
456
+ }
457
+ this.state = 'BUSY';
458
+ this.events.emitEvent({ type: 'state', state: 'BUSY' });
459
+ try {
460
+ await this.hooks.runPreModel(this.messages);
461
+ const response = await this.provider.complete(this.messages, {
462
+ tools: this.getToolSchemas(),
463
+ system: this.system,
464
+ maxTokens: this.maxTokens,
465
+ temperature: this.temperature,
466
+ });
467
+ await this.hooks.runPostModel(response);
468
+ this.messages.push({
469
+ role: 'assistant',
470
+ content: response.content,
471
+ });
472
+ // Emit text events
473
+ const textBlocks = response.content.filter((c) => c.type === 'text');
474
+ for (const block of textBlocks) {
475
+ this.events.emitEvent({ type: 'text', text: block.text });
476
+ }
477
+ // Emit usage
478
+ if (response.usage) {
479
+ this.events.emitEvent({
480
+ type: 'usage',
481
+ data: {
482
+ input_tokens: response.usage.input_tokens,
483
+ output_tokens: response.usage.output_tokens,
484
+ total_tokens: response.usage.input_tokens + response.usage.output_tokens,
485
+ },
486
+ });
487
+ }
488
+ const toolUses = response.content.filter((c) => c.type === 'tool_use');
489
+ if (toolUses.length > 0) {
490
+ const results = await this.executeTools(toolUses);
491
+ this.messages.push({
492
+ role: 'user',
493
+ content: results,
494
+ });
495
+ this.stepCount++;
496
+ this.lastSfpIndex = this.messages.length - 1;
497
+ this.events.emitEvent({ type: 'commit', sfpIndex: this.lastSfpIndex });
498
+ await this.persistMessages();
499
+ this.events.emitEvent({
500
+ type: 'messages_update',
501
+ messageCount: this.messages.length,
502
+ lastSfpIndex: this.lastSfpIndex,
503
+ added: 1,
504
+ });
505
+ // Continue next step
506
+ this.state = 'READY';
507
+ return this.step();
508
+ }
509
+ else {
510
+ // No tools, this is SFP
511
+ this.lastSfpIndex = this.messages.length - 1;
512
+ this.events.emitEvent({ type: 'commit', sfpIndex: this.lastSfpIndex });
513
+ await this.persistMessages();
514
+ this.events.emitEvent({
515
+ type: 'messages_update',
516
+ messageCount: this.messages.length,
517
+ lastSfpIndex: this.lastSfpIndex,
518
+ });
519
+ }
520
+ }
521
+ catch (error) {
522
+ this.events.emitEvent({
523
+ type: 'error',
524
+ kind: 'ProviderError',
525
+ message: error.message,
526
+ hint: error.stack,
527
+ });
528
+ }
529
+ finally {
530
+ this.state = 'READY';
531
+ this.events.emitEvent({ type: 'state', state: 'READY' });
532
+ }
533
+ }
534
+ async executeTools(toolUses) {
535
+ const results = [];
536
+ for (const use of toolUses) {
537
+ if (use.type !== 'tool_use')
538
+ continue;
539
+ const tu = use;
540
+ const tool = this.tools.get(tu.name);
541
+ this.events.emitEvent({ type: 'tool_use', id: tu.id, name: tu.name, input: tu.input });
542
+ if (!tool) {
543
+ results.push({
544
+ type: 'tool_result',
545
+ tool_use_id: tu.id,
546
+ content: { error: `Tool not found: ${tu.name}` },
547
+ is_error: true,
548
+ });
549
+ continue;
550
+ }
551
+ const call = {
552
+ id: tu.id,
553
+ name: tu.name,
554
+ args: tu.input,
555
+ sessionId: this.sessionId,
556
+ };
557
+ const ctx = {
558
+ sessionId: this.sessionId,
559
+ sandbox: this.sandbox,
560
+ agent: this,
561
+ };
562
+ // Run preToolUse hooks
563
+ const hookDecision = await this.hooks.runPreToolUse(call, ctx);
564
+ if (hookDecision) {
565
+ if ('decision' in hookDecision) {
566
+ if (hookDecision.decision === 'ask') {
567
+ // Pause and wait for permission
568
+ await this.requestPermission(call, hookDecision.meta);
569
+ // After permission granted, continue
570
+ }
571
+ else if (hookDecision.decision === 'deny') {
572
+ const result = {
573
+ type: 'tool_result',
574
+ tool_use_id: tu.id,
575
+ content: hookDecision.toolResult || { error: hookDecision.reason || 'Denied by policy' },
576
+ is_error: true,
577
+ };
578
+ results.push(result);
579
+ this.events.emitEvent({
580
+ type: 'tool_result',
581
+ id: tu.id,
582
+ name: tu.name,
583
+ ok: false,
584
+ content: result.content,
585
+ });
586
+ continue;
587
+ }
588
+ }
589
+ else if ('result' in hookDecision) {
590
+ // Pre-computed result
591
+ const result = {
592
+ type: 'tool_result',
593
+ tool_use_id: tu.id,
594
+ content: hookDecision.result,
595
+ };
596
+ results.push(result);
597
+ this.events.emitEvent({
598
+ type: 'tool_result',
599
+ id: tu.id,
600
+ name: tu.name,
601
+ ok: true,
602
+ content: result.content,
603
+ });
604
+ continue;
605
+ }
606
+ }
607
+ // Execute tool
608
+ try {
609
+ const startTime = Date.now();
610
+ const res = await tool.exec(call.args, ctx);
611
+ const duration = Date.now() - startTime;
612
+ let outcome = {
613
+ id: tu.id,
614
+ name: tu.name,
615
+ ok: true,
616
+ content: res,
617
+ duration_ms: duration,
618
+ };
619
+ // Run postToolUse hooks
620
+ outcome = await this.hooks.runPostToolUse(outcome, ctx);
621
+ const result = {
622
+ type: 'tool_result',
623
+ tool_use_id: tu.id,
624
+ content: outcome.content,
625
+ };
626
+ results.push(result);
627
+ this.events.emitEvent({
628
+ type: 'tool_result',
629
+ id: tu.id,
630
+ name: tu.name,
631
+ ok: true,
632
+ content: outcome.content,
633
+ duration_ms: outcome.duration_ms,
634
+ });
635
+ }
636
+ catch (error) {
637
+ const result = {
638
+ type: 'tool_result',
639
+ tool_use_id: tu.id,
640
+ content: { error: error.message },
641
+ is_error: true,
642
+ };
643
+ results.push(result);
644
+ this.events.emitEvent({
645
+ type: 'tool_result',
646
+ id: tu.id,
647
+ name: tu.name,
648
+ ok: false,
649
+ content: result.content,
650
+ });
651
+ }
652
+ }
653
+ return results;
654
+ }
655
+ async requestPermission(call, meta) {
656
+ return new Promise((resolve) => {
657
+ const respondFn = async (decision, note) => {
658
+ this.events.emitEvent({ type: 'permission_decision', id: call.id, decision, by: 'respond' });
659
+ resolve();
660
+ };
661
+ this.pendingPermissions.set(call.id, (decision, note) => {
662
+ respondFn(decision, note);
663
+ });
664
+ this.state = 'PAUSED';
665
+ this.events.emitEvent({
666
+ type: 'permission_ask',
667
+ id: call.id,
668
+ tool: call.name,
669
+ args: call.args,
670
+ meta,
671
+ respond: respondFn,
672
+ });
673
+ this.events.emitEvent({ type: 'state', state: 'PAUSED' });
674
+ });
675
+ }
676
+ getToolSchemas() {
677
+ return Array.from(this.tools.values()).map((tool) => ({
678
+ name: tool.name,
679
+ description: tool.description,
680
+ input_schema: tool.input_schema,
681
+ }));
682
+ }
683
+ async persistMessages() {
684
+ await this.store.saveMessages(this.sessionId, this.messages);
685
+ }
686
+ }
687
+ exports.Agent = Agent;
@@ -0,0 +1,19 @@
1
+ import { AgentEvent, AgentEventKind, Timeline } from '../core/types';
2
+ import { Store } from '../infra/store';
3
+ import { EventEmitter } from 'events';
4
+ export declare class EventBus extends EventEmitter {
5
+ private cursor;
6
+ private timeline;
7
+ private subscribers;
8
+ private store?;
9
+ private sessionId?;
10
+ setStore(store: Store, sessionId: string): void;
11
+ emitEvent(event: any): number;
12
+ subscribe(opts?: {
13
+ since?: number;
14
+ kinds?: AgentEventKind[];
15
+ }): AsyncIterable<AgentEvent>;
16
+ getTimeline(since?: number): Timeline[];
17
+ getCursor(): number;
18
+ reset(): void;
19
+ }