@nimbalyst/extension-sdk 0.2.0 → 0.2.2

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.
Files changed (79) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +32 -0
  3. package/dist/__tests__/createTextCollabContentAdapter.test.d.ts +2 -0
  4. package/dist/__tests__/createTextCollabContentAdapter.test.d.ts.map +1 -0
  5. package/dist/__tests__/createTextCollabContentAdapter.test.js +60 -0
  6. package/dist/__tests__/externalsPlugin.test.d.ts +2 -0
  7. package/dist/__tests__/externalsPlugin.test.d.ts.map +1 -0
  8. package/dist/__tests__/externalsPlugin.test.js +16 -0
  9. package/dist/__tests__/fileDirectoryTree.test.d.ts +2 -0
  10. package/dist/__tests__/fileDirectoryTree.test.d.ts.map +1 -0
  11. package/dist/__tests__/fileDirectoryTree.test.js +54 -0
  12. package/dist/__tests__/hasSeedableContent.test.d.ts +2 -0
  13. package/dist/__tests__/hasSeedableContent.test.d.ts.map +1 -0
  14. package/dist/__tests__/hasSeedableContent.test.js +25 -0
  15. package/dist/__tests__/manifestValidation.agentProviders.test.d.ts +2 -0
  16. package/dist/__tests__/manifestValidation.agentProviders.test.d.ts.map +1 -0
  17. package/dist/__tests__/manifestValidation.agentProviders.test.js +44 -0
  18. package/dist/agents/AgentProtocol.d.ts +233 -0
  19. package/dist/agents/AgentProtocol.d.ts.map +1 -0
  20. package/dist/agents/AgentProtocol.js +23 -0
  21. package/dist/agents/AgentProtocolHost.d.ts +190 -0
  22. package/dist/agents/AgentProtocolHost.d.ts.map +1 -0
  23. package/dist/agents/AgentProtocolHost.js +42 -0
  24. package/dist/agents/index.d.ts +26 -0
  25. package/dist/agents/index.d.ts.map +1 -0
  26. package/dist/agents/index.js +24 -0
  27. package/dist/collab/createTextCollabContentAdapter.d.ts +26 -0
  28. package/dist/collab/createTextCollabContentAdapter.d.ts.map +1 -0
  29. package/dist/collab/createTextCollabContentAdapter.js +79 -0
  30. package/dist/externalsPlugin.js +10 -0
  31. package/dist/fileDirectoryTree.d.ts +19 -0
  32. package/dist/fileDirectoryTree.d.ts.map +1 -0
  33. package/dist/fileDirectoryTree.js +98 -0
  34. package/dist/index.d.ts +5 -0
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +7 -0
  37. package/dist/manifestValidation.d.ts +118 -0
  38. package/dist/manifestValidation.d.ts.map +1 -0
  39. package/dist/manifestValidation.js +475 -0
  40. package/dist/trackerReferences.d.ts +32 -0
  41. package/dist/trackerReferences.d.ts.map +1 -0
  42. package/dist/trackerReferences.js +7 -0
  43. package/dist/types/collab.d.ts +138 -0
  44. package/dist/types/collab.d.ts.map +1 -0
  45. package/dist/types/collab.js +1 -0
  46. package/dist/types/editor.d.ts +81 -0
  47. package/dist/types/editor.d.ts.map +1 -1
  48. package/dist/types/editors.d.ts +4 -0
  49. package/dist/types/editors.d.ts.map +1 -1
  50. package/dist/types/extension.d.ts +364 -5
  51. package/dist/types/extension.d.ts.map +1 -1
  52. package/dist/types/extension.js +11 -1
  53. package/dist/types/index.d.ts +3 -0
  54. package/dist/types/index.d.ts.map +1 -1
  55. package/dist/types/index.js +3 -0
  56. package/dist/types/panel.d.ts +50 -0
  57. package/dist/types/panel.d.ts.map +1 -1
  58. package/dist/types/permissions.d.ts +119 -0
  59. package/dist/types/permissions.d.ts.map +1 -0
  60. package/dist/types/permissions.js +33 -0
  61. package/dist/types/theme.d.ts +50 -0
  62. package/dist/types/theme.d.ts.map +1 -1
  63. package/dist/types/theme.js +7 -1
  64. package/dist/types/trackerImporter.d.ts +147 -0
  65. package/dist/types/trackerImporter.d.ts.map +1 -0
  66. package/dist/types/trackerImporter.js +33 -0
  67. package/dist/useCollaborativeEditor.d.ts +84 -30
  68. package/dist/useCollaborativeEditor.d.ts.map +1 -1
  69. package/dist/useCollaborativeEditor.js +98 -7
  70. package/dist/validate.browser.d.ts +5 -0
  71. package/dist/validate.browser.d.ts.map +1 -0
  72. package/dist/validate.browser.js +27 -0
  73. package/dist/validate.d.ts +2 -8
  74. package/dist/validate.d.ts.map +1 -1
  75. package/dist/validate.js +117 -0
  76. package/dist/validationTypes.d.ts +9 -0
  77. package/dist/validationTypes.d.ts.map +1 -0
  78. package/dist/validationTypes.js +1 -0
  79. package/package.json +8 -1
package/CHANGELOG.md CHANGED
@@ -8,12 +8,32 @@ The SDK is versioned independently of the Nimbalyst app. Each release declares i
8
8
 
9
9
  | SDK version | Minimum Nimbalyst app version |
10
10
  | --- | --- |
11
+ | 0.2.2 | 0.58.5 |
12
+ | 0.2.1 | 0.58.5 |
11
13
  | 0.2.0 | 0.58.5 |
12
14
  | 0.1.5 | 0.58.5 |
13
15
  | 0.1.0 | 0.58.5 |
14
16
 
15
17
  ## [Unreleased]
16
18
 
19
+ ## [0.2.2]
20
+
21
+ ### Added
22
+
23
+ - Host-provided tracker reference chips and pickers let extensions persist stable item keys while using Nimbalyst's live metadata and navigation.
24
+
25
+ ## [0.2.1]
26
+
27
+ ### Added
28
+
29
+ - `ExtensionAITool.access` declares whether a tool uses filesystem, editor-read, or editor-write access; `readOnly` remains as a compatibility alias.
30
+ - `useCollaborativeEditor` accepts `{ codec, bind }` so an editor's pure collab codec is defined once and shared with the host's headless seeding; the previous `createBinding`/`initializeFromContent` config keeps working.
31
+ - `CollaborationContext.flushWithAck` (server-persisted flush) and optional `hasUndecodedContent`.
32
+
33
+ ### Fixed
34
+
35
+ - The first-open seed no longer runs from empty initial content or when the transport skipped payloads it could not decode — both cases wrote a default document over the shared room's real content.
36
+
17
37
  ## [0.2.0]
18
38
 
19
39
  Adds opt-in collaborative editing for custom editors. Backwards-compatible: extensions built against 0.2.0 continue to work on older Nimbalyst hosts -- the collaboration hook detects the absence of `host.collaboration` and reports `isCollaborative: false` so the editor falls back to local-only editing.
package/README.md CHANGED
@@ -93,6 +93,38 @@ const previewHost = createReadOnlyHost(code, {
93
93
 
94
94
  Type imports for props: `MonacoEditorProps`, `MonacoEditorConfig`, `MarkdownEditorProps`, `MarkdownEditorConfig` from `@nimbalyst/extension-sdk`.
95
95
 
96
+ ## Tracker References
97
+
98
+ Custom editors and panels can link their own data to tracker items without
99
+ querying Nimbalyst's internal tracker store. Persist only the reference keys
100
+ returned by the picker; chips resolve live metadata and open the item through
101
+ the host's contextual navigation.
102
+
103
+ ```tsx
104
+ import {
105
+ TrackerReferenceChip,
106
+ TrackerReferencePicker,
107
+ } from '@nimbalyst/extension-sdk';
108
+
109
+ <TrackerReferencePicker
110
+ value={trackerRefs}
111
+ onChange={setTrackerRefs}
112
+ disabled={host.readOnly}
113
+ />
114
+
115
+ {trackerRefs.map(referenceKey => (
116
+ <TrackerReferenceChip
117
+ key={referenceKey}
118
+ referenceKey={referenceKey}
119
+ variant="compact"
120
+ />
121
+ ))}
122
+ ```
123
+
124
+ The picker supports single or multiple selection, search, unresolved keys, and
125
+ read-only mutation state. `TrackerReferenceChip` supports `default` and
126
+ `compact` variants; both retain live preview and navigation behavior.
127
+
96
128
  ## AI Tool Example
97
129
 
98
130
  ```ts
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=createTextCollabContentAdapter.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createTextCollabContentAdapter.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/createTextCollabContentAdapter.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,60 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import * as Y from 'yjs';
3
+ import { createTextCollabContentAdapter } from '../collab/createTextCollabContentAdapter';
4
+ const adapter = createTextCollabContentAdapter({
5
+ documentType: 'calc.md',
6
+ fileExtensions: ['.calc.md'],
7
+ mimeType: 'text/markdown',
8
+ textField: 'content',
9
+ });
10
+ describe('createTextCollabContentAdapter', () => {
11
+ it('reports identity (documentType, extensions, version)', () => {
12
+ expect(adapter.documentType).toBe('calc.md');
13
+ expect(adapter.fileExtensions).toEqual(['.calc.md']);
14
+ expect(adapter.layoutVersion).toBe(1);
15
+ });
16
+ it('isEmpty is true for a fresh Y.Doc and false after seeding', () => {
17
+ const doc = new Y.Doc();
18
+ expect(adapter.isEmpty(doc)).toBe(true);
19
+ adapter.seedFromFile(doc, 'price = 100 USD\n');
20
+ expect(adapter.isEmpty(doc)).toBe(false);
21
+ });
22
+ it('round-trips file content through seed -> export -> plain text', () => {
23
+ const doc = new Y.Doc();
24
+ const source = '# Inputs\nprice = 100 USD\nqty = 3\n';
25
+ adapter.seedFromFile(doc, source);
26
+ expect(adapter.exportToFile(doc)).toBe(source);
27
+ expect(adapter.toPlainText(doc)).toBe(source);
28
+ });
29
+ it('decodes Uint8Array file sources', () => {
30
+ const doc = new Y.Doc();
31
+ const source = 'total = price * qty\n';
32
+ adapter.seedFromFile(doc, new TextEncoder().encode(source));
33
+ expect(adapter.exportToFile(doc)).toBe(source);
34
+ });
35
+ it('seedFromFile is a no-op when the Y.Text is already populated (open race)', () => {
36
+ const doc = new Y.Doc();
37
+ adapter.seedFromFile(doc, 'first');
38
+ adapter.seedFromFile(doc, 'second');
39
+ expect(adapter.exportToFile(doc)).toBe('first');
40
+ });
41
+ it('applyFromFile replaces existing content on a populated Y.Doc', () => {
42
+ const doc = new Y.Doc();
43
+ adapter.seedFromFile(doc, 'old content');
44
+ adapter.applyFromFile(doc, 'brand new content');
45
+ expect(adapter.exportToFile(doc)).toBe('brand new content');
46
+ });
47
+ it('does not re-seed a doc that already received content via sync (race guard)', () => {
48
+ // Models the bootstrap race on a SINGLE shared doc: another client's seed
49
+ // arrives over the wire first, then this client (which had decided the doc
50
+ // was empty) calls seedFromFile. The length guard makes the late seed a
51
+ // no-op, so the synced content is preserved verbatim (no concatenation).
52
+ // The hook layer additionally re-checks isEmpty before seeding.
53
+ const remote = new Y.Doc();
54
+ adapter.seedFromFile(remote, 'a = 1\nb = 2\n');
55
+ const local = new Y.Doc();
56
+ Y.applyUpdate(local, Y.encodeStateAsUpdate(remote)); // remote seed arrives
57
+ adapter.seedFromFile(local, 'a = 1\nb = 2\n'); // late local seed -> no-op
58
+ expect(adapter.exportToFile(local)).toBe('a = 1\nb = 2\n');
59
+ });
60
+ });
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=externalsPlugin.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"externalsPlugin.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/externalsPlugin.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,16 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { nimbalystExternalsPlugin } from '../externalsPlugin';
3
+ describe('nimbalystExternalsPlugin runtime bridge', () => {
4
+ it('emits named exports for host-provided tracker reference APIs', async () => {
5
+ const plugin = nimbalystExternalsPlugin();
6
+ const resolveId = plugin.resolveId;
7
+ const load = plugin.load;
8
+ const id = await resolveId('@nimbalyst/runtime', undefined, {});
9
+ expect(id).toBe('\0nimbalyst-external:@nimbalyst/runtime');
10
+ const source = await load(id);
11
+ expect(source).toContain('export const TrackerReferenceChip');
12
+ expect(source).toContain('export const TrackerReferencePicker');
13
+ expect(source).toContain('export const useResolvedTrackerReference');
14
+ expect(source).toContain('export const navigateToTrackerReference');
15
+ });
16
+ });
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=fileDirectoryTree.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fileDirectoryTree.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/fileDirectoryTree.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,54 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { buildFileDirectoryTree, getFileDirectoryPaths, getFilePathBasename, getWorkspaceRelativeFilePath, } from '../fileDirectoryTree';
3
+ const buildTree = (files, workspacePath) => buildFileDirectoryTree(files.map(filePath => ({ filePath })), file => file.filePath, workspacePath);
4
+ describe('file path helpers', () => {
5
+ it('normalizes Unix, Windows, and mixed separators', () => {
6
+ expect(getWorkspaceRelativeFilePath('/repo/src/App.tsx', '/repo')).toBe('src/App.tsx');
7
+ expect(getWorkspaceRelativeFilePath('C:\\repo\\src\\App.tsx', 'C:\\repo'))
8
+ .toBe('src/App.tsx');
9
+ expect(getWorkspaceRelativeFilePath('C:\\repo/src\\App.tsx', 'C:\\repo\\'))
10
+ .toBe('src/App.tsx');
11
+ });
12
+ it('compares Windows drive paths case-insensitively', () => {
13
+ expect(getWorkspaceRelativeFilePath('c:\\Repo\\src\\App.tsx', 'C:\\repo'))
14
+ .toBe('src/App.tsx');
15
+ });
16
+ it('does not strip a partial workspace prefix', () => {
17
+ expect(getWorkspaceRelativeFilePath('/repo-copy/src/App.tsx', '/repo'))
18
+ .toBe('/repo-copy/src/App.tsx');
19
+ });
20
+ it('gets basenames from Unix and Windows paths', () => {
21
+ expect(getFilePathBasename('packages/runtime/index.ts')).toBe('index.ts');
22
+ expect(getFilePathBasename('packages\\runtime\\index.ts')).toBe('index.ts');
23
+ });
24
+ });
25
+ describe('buildFileDirectoryTree', () => {
26
+ it('groups Windows files with duplicate basenames under their directories', () => {
27
+ const tree = buildTree([
28
+ 'C:\\repo\\skills\\one\\SKILL.md',
29
+ 'C:\\repo\\skills\\two\\SKILL.md',
30
+ 'C:\\repo\\README.md',
31
+ ], 'C:\\repo');
32
+ expect(tree.displayPath).toBe('');
33
+ expect(tree.files.map(file => file.filePath)).toEqual(['C:\\repo\\README.md']);
34
+ expect([...tree.subdirectories.keys()]).toEqual(['skills']);
35
+ expect(getFileDirectoryPaths(tree)).toEqual(['skills', 'skills/one', 'skills/two']);
36
+ expect(tree.fileCount).toBe(3);
37
+ expect(tree.subdirectories.get('skills')?.fileCount).toBe(2);
38
+ });
39
+ it('groups workspace-relative Windows paths for commit proposals', () => {
40
+ const tree = buildTree([
41
+ 'packages\\runtime\\SKILL.md',
42
+ 'packages\\electron\\SKILL.md',
43
+ ]);
44
+ expect(tree.displayPath).toBe('packages');
45
+ expect(getFileDirectoryPaths(tree)).toEqual(['packages', 'packages/runtime', 'packages/electron']);
46
+ });
47
+ it('collapses a single-child Unix directory chain', () => {
48
+ const tree = buildTree(['/repo/packages/runtime/src/index.ts'], '/repo');
49
+ expect(tree.displayPath).toBe('packages/runtime/src');
50
+ expect(tree.path).toBe('packages/runtime/src');
51
+ expect(tree.fileCount).toBe(1);
52
+ expect(tree.files).toHaveLength(1);
53
+ });
54
+ });
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=hasSeedableContent.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hasSeedableContent.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/hasSeedableContent.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,25 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { hasSeedableContent } from '../useCollaborativeEditor';
3
+ /**
4
+ * NIM-1520 fallout guard: a host with no bytes for a collab doc returns ''
5
+ * from loadInitialContent; seeding from that writes a DEFAULT document over
6
+ * the room's real content ("Untitled map" clobber). Empty content must never
7
+ * be considered seedable.
8
+ */
9
+ describe('hasSeedableContent', () => {
10
+ it('rejects null/undefined/empty/whitespace strings', () => {
11
+ expect(hasSeedableContent(null)).toBe(false);
12
+ expect(hasSeedableContent(undefined)).toBe(false);
13
+ expect(hasSeedableContent('')).toBe(false);
14
+ expect(hasSeedableContent(' \n\t')).toBe(false);
15
+ });
16
+ it('rejects empty binary buffers', () => {
17
+ expect(hasSeedableContent(new ArrayBuffer(0))).toBe(false);
18
+ expect(hasSeedableContent(new Uint8Array(0))).toBe(false);
19
+ });
20
+ it('accepts real content', () => {
21
+ expect(hasSeedableContent('# Title')).toBe(true);
22
+ expect(hasSeedableContent(new Uint8Array([1, 2, 3]))).toBe(true);
23
+ expect(hasSeedableContent(new ArrayBuffer(8))).toBe(true);
24
+ });
25
+ });
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=manifestValidation.agentProviders.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifestValidation.agentProviders.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/manifestValidation.agentProviders.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,44 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { validateAgentProviders } from '../manifestValidation';
3
+ // The validator must agree with the AiAgentProviderContribution /
4
+ // AiAgentProviderModel types: the provider label field is `displayName`, and
5
+ // model entries carry no per-entry `provider`. A manifest matching the shipped
6
+ // gemini-antigravity contribution should pass cleanly. Before the alignment,
7
+ // the validator required `name` and `model.provider`, so the real manifest
8
+ // failed its own validator (#558 review, point 1).
9
+ const backendModules = [{ id: 'antigravity-server', entry: 'backend/index.js' }];
10
+ function geminiLikeProvider(overrides = {}) {
11
+ return {
12
+ id: 'antigravity-gemini-agent',
13
+ displayName: 'Gemini',
14
+ platform: 'antigravity-gemini',
15
+ backendModuleId: 'antigravity-server',
16
+ modelDiscovery: 'static',
17
+ models: [
18
+ { id: 'antigravity-gemini-agent:gemini-3-flash-agent', name: 'Gemini 3.5 Flash (High)', default: true },
19
+ { id: 'antigravity-gemini-agent:gemini-3.5-flash-low', name: 'Gemini 3.5 Flash (Medium)' },
20
+ ],
21
+ ...overrides,
22
+ };
23
+ }
24
+ describe('validateAgentProviders - alignment with the SDK type (#558)', () => {
25
+ it('accepts a provider that uses displayName and models without a provider field', () => {
26
+ const issues = validateAgentProviders([geminiLikeProvider()], backendModules);
27
+ expect(issues).toEqual([]);
28
+ });
29
+ it('flags a provider missing displayName', () => {
30
+ const { displayName, ...noDisplayName } = geminiLikeProvider();
31
+ const issues = validateAgentProviders([noDisplayName], backendModules);
32
+ expect(issues.some((i) => i.message.includes('displayName'))).toBe(true);
33
+ });
34
+ it('does not require a per-model provider field', () => {
35
+ // A model entry with only id + name is valid; the host derives the
36
+ // provider from the contribution id.
37
+ const issues = validateAgentProviders([geminiLikeProvider({ models: [{ id: 'm1', name: 'Model One' }] })], backendModules);
38
+ expect(issues).toEqual([]);
39
+ });
40
+ it('still requires a model name', () => {
41
+ const issues = validateAgentProviders([geminiLikeProvider({ models: [{ id: 'm1' }] })], backendModules);
42
+ expect(issues.some((i) => i.message.includes('.name must be a non-empty string'))).toBe(true);
43
+ });
44
+ });
@@ -0,0 +1,233 @@
1
+ /**
2
+ * Protocol Interface for Agent SDK Adapters
3
+ *
4
+ * This interface normalizes the differences between various agent SDKs
5
+ * (Claude Agent SDK, OpenAI Codex SDK) to provide a unified abstraction
6
+ * layer for agent providers.
7
+ *
8
+ * The protocol adapters isolate platform-specific SDK details from the
9
+ * provider implementations, making it easier to:
10
+ * - Add new agent SDKs
11
+ * - Update SDK versions without touching provider logic
12
+ * - Test providers with mock protocols
13
+ * - Share common infrastructure across providers
14
+ *
15
+ * Ownership note: this module is the canonical home of the protocol
16
+ * contract. The runtime re-exports these types via
17
+ * `@nimbalyst/runtime/ai/server/protocols/ProtocolInterface` so that
18
+ * existing runtime imports keep working without source churn, but the
19
+ * SDK now owns the type bodies. Adding a new field, changing a tag, or
20
+ * tightening a discriminator happens here first; the runtime picks it
21
+ * up via the re-export.
22
+ */
23
+ /**
24
+ * MCP server configuration
25
+ */
26
+ export interface MCPServerConfig {
27
+ command: string;
28
+ args?: string[];
29
+ env?: Record<string, string>;
30
+ [key: string]: unknown;
31
+ }
32
+ /**
33
+ * Platform-specific session data for internal use
34
+ */
35
+ export interface RawProtocolSession {
36
+ [key: string]: unknown;
37
+ }
38
+ /**
39
+ * Structured result from tool execution
40
+ */
41
+ export interface ToolResult {
42
+ success: boolean;
43
+ result?: unknown;
44
+ output?: unknown;
45
+ error?: string | unknown;
46
+ status?: string;
47
+ command?: string;
48
+ exit_code?: number;
49
+ changes?: unknown;
50
+ query?: string;
51
+ action?: unknown;
52
+ fileSnapshots?: Record<string, {
53
+ content: string | null;
54
+ error?: string;
55
+ isBinary?: boolean;
56
+ truncated?: boolean;
57
+ }>;
58
+ }
59
+ /**
60
+ * Options for creating or resuming a session
61
+ */
62
+ export interface SessionOptions {
63
+ /** Working directory path for the session */
64
+ workspacePath: string;
65
+ /** Model identifier (e.g., 'sonnet', 'gpt-5') */
66
+ model?: string;
67
+ /** System prompt to initialize the agent */
68
+ systemPrompt?: string;
69
+ /** Abort signal for cancelling the session */
70
+ abortSignal?: AbortSignal;
71
+ /** Permission mode for tool approvals ('ask', 'auto', 'plan') */
72
+ permissionMode?: string;
73
+ /** MCP server configurations */
74
+ mcpServers?: Record<string, MCPServerConfig>;
75
+ /** Environment variables for the session */
76
+ env?: Record<string, string>;
77
+ /** Tools to allow (whitelist) */
78
+ allowedTools?: string[];
79
+ /** Tools to disallow (blacklist) */
80
+ disallowedTools?: string[];
81
+ /** Platform-specific options that don't fit the common schema */
82
+ raw?: Record<string, unknown>;
83
+ }
84
+ /**
85
+ * Attachment shape used by ProtocolMessage.
86
+ *
87
+ * Inlined into the SDK (rather than re-imported from the runtime's
88
+ * `ChatAttachment`) so the protocol contract has no dependency on
89
+ * runtime types. The runtime's `ChatAttachment` is structurally
90
+ * assignable to this shape, so existing runtime call sites that pass
91
+ * `ChatAttachment[]` continue to type-check at the SDK boundary.
92
+ */
93
+ export interface ProtocolAttachment {
94
+ id: string;
95
+ filename: string;
96
+ filepath: string;
97
+ mimeType: string;
98
+ size: number;
99
+ type: 'image' | 'pdf' | 'document';
100
+ thumbnail?: string;
101
+ addedAt: number;
102
+ }
103
+ /**
104
+ * Message sent to the agent
105
+ */
106
+ export interface ProtocolMessage {
107
+ /** Text content of the message */
108
+ content: string;
109
+ /** Optional attachments (images, PDFs, documents) */
110
+ attachments?: ProtocolAttachment[];
111
+ /** Session ID for logging and tracking */
112
+ sessionId?: string;
113
+ /** AI mode when message was sent ('planning' or 'agent' or 'auto') */
114
+ mode?: 'planning' | 'agent' | 'auto';
115
+ /**
116
+ * Abort signal for THIS turn. Protocol sessions are cached across turns, so
117
+ * a signal passed at session creation goes stale after the first turn --
118
+ * per-message is the only correct place to carry it.
119
+ */
120
+ abortSignal?: AbortSignal;
121
+ }
122
+ /**
123
+ * Session created or resumed by the protocol
124
+ */
125
+ export interface ProtocolSession {
126
+ /** Platform-specific session identifier */
127
+ id: string;
128
+ /** Platform identifier (e.g., 'claude-sdk', 'codex-sdk') */
129
+ platform: string;
130
+ /** Platform-specific session data (for internal use) */
131
+ raw?: RawProtocolSession;
132
+ }
133
+ /**
134
+ * Event types emitted during message streaming
135
+ */
136
+ export type ProtocolEventType = 'raw_event' | 'text' | 'reasoning' | 'tool_call' | 'tool_result' | 'error' | 'complete' | 'usage' | 'planning_mode_entered' | 'planning_mode_exited';
137
+ /**
138
+ * Event emitted during message streaming
139
+ */
140
+ export interface ProtocolEvent {
141
+ /** Event type */
142
+ type: ProtocolEventType;
143
+ /** Text content (for 'text' events) */
144
+ content?: string;
145
+ /** Tool call data (for 'tool_call' events) */
146
+ toolCall?: {
147
+ id?: string;
148
+ name: string;
149
+ arguments?: Record<string, any>;
150
+ result?: ToolResult | string;
151
+ };
152
+ /** Tool result data (for 'tool_result' events) */
153
+ toolResult?: {
154
+ id?: string;
155
+ name: string;
156
+ result?: ToolResult | string;
157
+ };
158
+ /** Error message (for 'error' events) */
159
+ error?: string;
160
+ /** Token usage (for 'usage' or 'complete' events) */
161
+ usage?: {
162
+ input_tokens: number;
163
+ output_tokens: number;
164
+ total_tokens: number;
165
+ };
166
+ /** Current context fill tokens for this turn (provider-reported snapshot) */
167
+ contextFillTokens?: number;
168
+ /** Maximum context window for the active model */
169
+ contextWindow?: number;
170
+ /** Additional metadata */
171
+ metadata?: Record<string, unknown>;
172
+ }
173
+ /**
174
+ * Agent Protocol Interface
175
+ *
176
+ * All agent SDK adapters must implement this interface to provide
177
+ * a consistent abstraction layer for agent providers.
178
+ */
179
+ export interface AgentProtocol {
180
+ /**
181
+ * Platform identifier (e.g., 'claude-sdk', 'codex-sdk')
182
+ */
183
+ readonly platform: string;
184
+ /**
185
+ * Create a new session
186
+ *
187
+ * @param options - Session configuration
188
+ * @returns Protocol session with platform-specific ID
189
+ */
190
+ createSession(options: SessionOptions): Promise<ProtocolSession>;
191
+ /**
192
+ * Resume an existing session
193
+ *
194
+ * @param sessionId - Platform-specific session ID to resume
195
+ * @param options - Session configuration
196
+ * @returns Protocol session
197
+ */
198
+ resumeSession(sessionId: string, options: SessionOptions): Promise<ProtocolSession>;
199
+ /**
200
+ * Fork an existing session (create a branch)
201
+ *
202
+ * Not all platforms support forking. If unsupported, implementations
203
+ * should either throw an error or create a new session.
204
+ *
205
+ * @param sessionId - Platform-specific session ID to fork from
206
+ * @param options - Session configuration for the fork
207
+ * @returns New protocol session branched from the source
208
+ */
209
+ forkSession(sessionId: string, options: SessionOptions): Promise<ProtocolSession>;
210
+ /**
211
+ * Send a message and receive streaming events
212
+ *
213
+ * @param session - Active protocol session
214
+ * @param message - Message to send
215
+ * @returns Async iterable of protocol events
216
+ */
217
+ sendMessage(session: ProtocolSession, message: ProtocolMessage): AsyncIterable<ProtocolEvent>;
218
+ /**
219
+ * Abort an active session
220
+ *
221
+ * @param session - Session to abort
222
+ */
223
+ abortSession(session: ProtocolSession): void;
224
+ /**
225
+ * Clean up session resources
226
+ *
227
+ * Called when a session is deleted or no longer needed.
228
+ *
229
+ * @param session - Session to clean up
230
+ */
231
+ cleanupSession(session: ProtocolSession): void;
232
+ }
233
+ //# sourceMappingURL=AgentProtocol.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AgentProtocol.d.ts","sourceRoot":"","sources":["../../src/agents/AgentProtocol.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Protocol Interface for Agent SDK Adapters
3
+ *
4
+ * This interface normalizes the differences between various agent SDKs
5
+ * (Claude Agent SDK, OpenAI Codex SDK) to provide a unified abstraction
6
+ * layer for agent providers.
7
+ *
8
+ * The protocol adapters isolate platform-specific SDK details from the
9
+ * provider implementations, making it easier to:
10
+ * - Add new agent SDKs
11
+ * - Update SDK versions without touching provider logic
12
+ * - Test providers with mock protocols
13
+ * - Share common infrastructure across providers
14
+ *
15
+ * Ownership note: this module is the canonical home of the protocol
16
+ * contract. The runtime re-exports these types via
17
+ * `@nimbalyst/runtime/ai/server/protocols/ProtocolInterface` so that
18
+ * existing runtime imports keep working without source churn, but the
19
+ * SDK now owns the type bodies. Adding a new field, changing a tag, or
20
+ * tightening a discriminator happens here first; the runtime picks it
21
+ * up via the re-export.
22
+ */
23
+ export {};