@ottimis/jack-provider-sdk 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 +62 -0
- package/dist/backend.d.ts +256 -0
- package/dist/backend.d.ts.map +1 -0
- package/dist/backend.js +28 -0
- package/dist/backend.js.map +1 -0
- package/dist/cjs/backend.js +29 -0
- package/dist/cjs/backend.js.map +1 -0
- package/dist/cjs/index.js +42 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/provider.js +20 -0
- package/dist/cjs/provider.js.map +1 -0
- package/dist/cjs/spawner.js +41 -0
- package/dist/cjs/spawner.js.map +1 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -0
- package/dist/provider.d.ts +651 -0
- package/dist/provider.d.ts.map +1 -0
- package/dist/provider.js +19 -0
- package/dist/provider.js.map +1 -0
- package/dist/spawner.d.ts +55 -0
- package/dist/spawner.d.ts.map +1 -0
- package/dist/spawner.js +37 -0
- package/dist/spawner.js.map +1 -0
- package/package.json +40 -0
- package/src/backend.ts +291 -0
- package/src/index.ts +34 -0
- package/src/provider.ts +700 -0
- package/src/spawner.ts +70 -0
package/dist/provider.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JackProvider — plugin contract for an AI provider integration.
|
|
3
|
+
*
|
|
4
|
+
* A provider package (in-tree `providers/claude/`, future external
|
|
5
|
+
* `jack-codex`, `jack-gemini`, …) registers a single `JackProvider` object
|
|
6
|
+
* that wires up everything the host needs to drive that AI:
|
|
7
|
+
*
|
|
8
|
+
* - one or more {@link BackendDescriptor}s (the wire-protocol implementations)
|
|
9
|
+
* - a {@link CapabilityMatrix} so the UI knows what features to show
|
|
10
|
+
* - a {@link ToolDescriptor} catalog so the renderer can map provider-native
|
|
11
|
+
* tool names to canonical Jack shapes
|
|
12
|
+
* - a {@link JackProvider.detect} probe so the gate UI can warn when the
|
|
13
|
+
* host lacks a usable installation
|
|
14
|
+
*
|
|
15
|
+
* This file is the boundary between Jack core and a provider package — keep
|
|
16
|
+
* it free of provider-specific imports.
|
|
17
|
+
*/
|
|
18
|
+
export {};
|
|
19
|
+
//# sourceMappingURL=provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ProcessSpawner — abstraction over "how we get a running provider CLI
|
|
3
|
+
* with stdin/stdout pipes attached". Consumed by every backend so they
|
|
4
|
+
* don't need to know whether the process runs locally or inside a Docker
|
|
5
|
+
* container.
|
|
6
|
+
*
|
|
7
|
+
* Design goals:
|
|
8
|
+
* - The shape matches the Anthropic SDK's `SpawnedProcess` / `SpawnOptions`
|
|
9
|
+
* exactly, so a single spawner can be fed to that SDK without
|
|
10
|
+
* translation. Other providers happily reuse the same shape.
|
|
11
|
+
* - The only Docker-aware code lives in the host's `docker/sandbox.ts`
|
|
12
|
+
* which exposes a `createDockerSpawner()` that returns a ProcessSpawner.
|
|
13
|
+
* - The host decides which spawner to use based on `session.sandboxed`
|
|
14
|
+
* and hands it to the provider via `AgentQueryOptions.spawner`.
|
|
15
|
+
*/
|
|
16
|
+
import type { Readable, Writable } from 'node:stream';
|
|
17
|
+
/**
|
|
18
|
+
* Minimal process handle that both `ChildProcess` (node) and the Anthropic
|
|
19
|
+
* SDK's `SpawnedProcess` satisfy. Deliberately identical to the SDK
|
|
20
|
+
* interface so that values of this type can be handed back to the SDK
|
|
21
|
+
* verbatim.
|
|
22
|
+
*/
|
|
23
|
+
export interface ProcessHandle {
|
|
24
|
+
stdin: Writable;
|
|
25
|
+
stdout: Readable;
|
|
26
|
+
readonly killed: boolean;
|
|
27
|
+
readonly exitCode: number | null;
|
|
28
|
+
kill(signal?: NodeJS.Signals): boolean;
|
|
29
|
+
on(event: 'exit', listener: (code: number | null, signal: NodeJS.Signals | null) => void): void;
|
|
30
|
+
on(event: 'error', listener: (error: Error) => void): void;
|
|
31
|
+
once(event: 'exit', listener: (code: number | null, signal: NodeJS.Signals | null) => void): void;
|
|
32
|
+
once(event: 'error', listener: (error: Error) => void): void;
|
|
33
|
+
off(event: 'exit', listener: (code: number | null, signal: NodeJS.Signals | null) => void): void;
|
|
34
|
+
off(event: 'error', listener: (error: Error) => void): void;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Arguments handed to a spawner. Matches the Anthropic SDK `SpawnOptions`
|
|
38
|
+
* shape so the same function can be plugged into `spawnClaudeCodeProcess`.
|
|
39
|
+
*/
|
|
40
|
+
export interface SpawnArgs {
|
|
41
|
+
command: string;
|
|
42
|
+
args: string[];
|
|
43
|
+
cwd?: string;
|
|
44
|
+
env: {
|
|
45
|
+
[k: string]: string | undefined;
|
|
46
|
+
};
|
|
47
|
+
signal: AbortSignal;
|
|
48
|
+
}
|
|
49
|
+
export type ProcessSpawner = (args: SpawnArgs) => ProcessHandle;
|
|
50
|
+
/**
|
|
51
|
+
* Default local spawner — plain `child_process.spawn`. The returned
|
|
52
|
+
* ChildProcess satisfies ProcessHandle because we pipe all three streams.
|
|
53
|
+
*/
|
|
54
|
+
export declare const localSpawner: ProcessSpawner;
|
|
55
|
+
//# sourceMappingURL=spawner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spawner.d.ts","sourceRoot":"","sources":["../src/spawner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAErD;;;;;GAKG;AACH,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,QAAQ,CAAA;IACf,MAAM,EAAE,QAAQ,CAAA;IAChB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAA;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IAChC,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,OAAO,GAAG,OAAO,CAAA;IACtC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,OAAO,GAAG,IAAI,KAAK,IAAI,GAAG,IAAI,CAAA;IAC/F,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,GAAG,IAAI,CAAA;IAC1D,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,OAAO,GAAG,IAAI,KAAK,IAAI,GAAG,IAAI,CAAA;IACjG,IAAI,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,GAAG,IAAI,CAAA;IAC5D,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,OAAO,GAAG,IAAI,KAAK,IAAI,GAAG,IAAI,CAAA;IAChG,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,GAAG,IAAI,CAAA;CAC5D;AAED;;;GAGG;AACH,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,EAAE,CAAA;IACd,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE;QAAE,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAA;KAAE,CAAA;IACxC,MAAM,EAAE,WAAW,CAAA;CACpB;AAED,MAAM,MAAM,cAAc,GAAG,CAAC,IAAI,EAAE,SAAS,KAAK,aAAa,CAAA;AAE/D;;;GAGG;AACH,eAAO,MAAM,YAAY,EAAE,cAY1B,CAAA"}
|
package/dist/spawner.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ProcessSpawner — abstraction over "how we get a running provider CLI
|
|
3
|
+
* with stdin/stdout pipes attached". Consumed by every backend so they
|
|
4
|
+
* don't need to know whether the process runs locally or inside a Docker
|
|
5
|
+
* container.
|
|
6
|
+
*
|
|
7
|
+
* Design goals:
|
|
8
|
+
* - The shape matches the Anthropic SDK's `SpawnedProcess` / `SpawnOptions`
|
|
9
|
+
* exactly, so a single spawner can be fed to that SDK without
|
|
10
|
+
* translation. Other providers happily reuse the same shape.
|
|
11
|
+
* - The only Docker-aware code lives in the host's `docker/sandbox.ts`
|
|
12
|
+
* which exposes a `createDockerSpawner()` that returns a ProcessSpawner.
|
|
13
|
+
* - The host decides which spawner to use based on `session.sandboxed`
|
|
14
|
+
* and hands it to the provider via `AgentQueryOptions.spawner`.
|
|
15
|
+
*/
|
|
16
|
+
import { spawn } from 'node:child_process';
|
|
17
|
+
/**
|
|
18
|
+
* Default local spawner — plain `child_process.spawn`. The returned
|
|
19
|
+
* ChildProcess satisfies ProcessHandle because we pipe all three streams.
|
|
20
|
+
*/
|
|
21
|
+
export const localSpawner = ({ command, args, cwd, env, signal }) => {
|
|
22
|
+
const cp = spawn(command, args, {
|
|
23
|
+
cwd,
|
|
24
|
+
env,
|
|
25
|
+
stdio: ['pipe', 'pipe', 'pipe']
|
|
26
|
+
});
|
|
27
|
+
signal.addEventListener('abort', () => {
|
|
28
|
+
if (!cp.killed) {
|
|
29
|
+
try {
|
|
30
|
+
cp.kill('SIGTERM');
|
|
31
|
+
}
|
|
32
|
+
catch { /* ignore */ }
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
return cp;
|
|
36
|
+
};
|
|
37
|
+
//# sourceMappingURL=spawner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spawner.js","sourceRoot":"","sources":["../src/spawner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,KAAK,EAAuC,MAAM,oBAAoB,CAAA;AAqC/E;;;GAGG;AACH,MAAM,CAAC,MAAM,YAAY,GAAmB,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE;IAClF,MAAM,EAAE,GAAmC,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE;QAC9D,GAAG;QACH,GAAG;QACH,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;KAChC,CAAC,CAAA;IACF,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE;QACpC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC;YACf,IAAI,CAAC;gBAAC,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;YAAC,CAAC;YAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;QACnD,CAAC;IACH,CAAC,CAAC,CAAA;IACF,OAAO,EAAE,CAAA;AACX,CAAC,CAAA"}
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ottimis/jack-provider-sdk",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Plugin contract for AI provider integrations in Jack — backend interface, capability matrix, spawner primitives, knowledge context. Consumed both by in-tree providers and external packages.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/ottimis/JACK-provider-sdk.git"
|
|
9
|
+
},
|
|
10
|
+
"type": "module",
|
|
11
|
+
"main": "./dist/index.js",
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"exports": {
|
|
14
|
+
".": {
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"import": "./dist/index.js",
|
|
17
|
+
"require": "./dist/cjs/index.js"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"dist",
|
|
22
|
+
"src",
|
|
23
|
+
"README.md"
|
|
24
|
+
],
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "pnpm clean && tsc && tsc -p tsconfig.cjs.json && node -e \"require('fs').writeFileSync('dist/cjs/package.json', JSON.stringify({type:'commonjs'}))\"",
|
|
27
|
+
"typecheck": "tsc --noEmit",
|
|
28
|
+
"test": "node --test --import tsx tests/*.test.ts",
|
|
29
|
+
"clean": "rm -rf dist"
|
|
30
|
+
},
|
|
31
|
+
"peerDependencies": {
|
|
32
|
+
"@ottimis/jack-chat-core": ">=0.5.5"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@ottimis/jack-chat-core": "^0.5.5",
|
|
36
|
+
"@types/node": "^22.14.1",
|
|
37
|
+
"tsx": "^4.19.2",
|
|
38
|
+
"typescript": "^5.8.3"
|
|
39
|
+
}
|
|
40
|
+
}
|
package/src/backend.ts
ADDED
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AgentBackend — abstraction that lets the host talk to an AI provider via
|
|
3
|
+
* one of its concrete backends (Claude SDK / Claude CLI / Codex / Gemini ACP / …).
|
|
4
|
+
*
|
|
5
|
+
* Every type on this surface is **provider-neutral**: no SDK/Claude type
|
|
6
|
+
* leaks past this boundary. Each provider package translates between its
|
|
7
|
+
* native wire format and these neutral types inside the backend
|
|
8
|
+
* implementation. The host never imports from a provider's native SDK
|
|
9
|
+
* directly.
|
|
10
|
+
*
|
|
11
|
+
* - The output stream is {@link NormalizedMessage} (parsed by the
|
|
12
|
+
* provider's translator).
|
|
13
|
+
* - The {@link AgentQueryOptions.canUseTool} callback receives a
|
|
14
|
+
* {@link NormalizedPermissionRequest} and resolves to a
|
|
15
|
+
* {@link NormalizedPermissionResult} — the provider does the wire
|
|
16
|
+
* translation on both sides.
|
|
17
|
+
* - The {@link AgentHooks} pipeline is fed {@link NormalizedHookEvent}s.
|
|
18
|
+
* - Provider-private spawn details (e.g. Claude SDK's `executable` +
|
|
19
|
+
* `pathToClaudeCodeExecutable`) ride in the
|
|
20
|
+
* {@link AgentQueryOptions.providerSpawnHints} escape hatch — the host
|
|
21
|
+
* populates them via `JackProvider.prepareSpawnOptions` and never
|
|
22
|
+
* inspects the contents.
|
|
23
|
+
*
|
|
24
|
+
* Selection happens in the host's `backendFactory` → which delegates to
|
|
25
|
+
* the provider registry.
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
import type { ProcessSpawner } from './spawner'
|
|
29
|
+
import type {
|
|
30
|
+
NormalizedMessage,
|
|
31
|
+
NormalizedPermissionRequest,
|
|
32
|
+
NormalizedPermissionResult,
|
|
33
|
+
NormalizedHookEvent
|
|
34
|
+
} from '@ottimis/jack-chat-core'
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Open string union — every provider declares its own backend ids. Today
|
|
38
|
+
* `'sdk'` and `'cli'` are Claude-specific; Gemini ships `'acp'`. The host
|
|
39
|
+
* resolves the active backend by id against the provider's `backends[]`
|
|
40
|
+
* list, so widening to `string` is required for non-Claude providers.
|
|
41
|
+
*/
|
|
42
|
+
export type BackendName = string
|
|
43
|
+
|
|
44
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
45
|
+
// Neutral option types
|
|
46
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
47
|
+
|
|
48
|
+
/** Permission gate behaviour. Strings the host may toggle live. */
|
|
49
|
+
export type AgentPermissionMode =
|
|
50
|
+
| 'default'
|
|
51
|
+
| 'acceptEdits'
|
|
52
|
+
| 'plan'
|
|
53
|
+
| 'bypassPermissions'
|
|
54
|
+
|
|
55
|
+
/** Settings layers the provider should consult at boot. */
|
|
56
|
+
export type AgentSettingSource = 'user' | 'project' | 'local'
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* System prompt shape: a plain string (provider replaces its default), or
|
|
60
|
+
* a preset envelope with an optional append (provider extends its default).
|
|
61
|
+
* The preset name is provider-specific; today only `'claude_code'` exists.
|
|
62
|
+
*/
|
|
63
|
+
export type AgentSystemPrompt =
|
|
64
|
+
| string
|
|
65
|
+
| { type: 'preset'; preset: string; append?: string }
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* MCP server configuration — opaque to the host. The host never inspects
|
|
69
|
+
* the inner shape; each provider validates / consumes its own format.
|
|
70
|
+
*/
|
|
71
|
+
export type AgentMcpServerConfig = unknown
|
|
72
|
+
|
|
73
|
+
/** Reasoning-effort knob. Provider-validated; not all providers honor every value. */
|
|
74
|
+
export type AgentEffortLevel = 'low' | 'medium' | 'high' | 'xhigh' | 'max'
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Hook handler — receives a normalized lifecycle event and may return an
|
|
78
|
+
* opaque object the provider interprets (e.g. `{ continue: false }` to
|
|
79
|
+
* abort a tool call). Most handlers just return `undefined`.
|
|
80
|
+
*/
|
|
81
|
+
export type AgentHookHandler = (event: NormalizedHookEvent) => Promise<unknown> | unknown
|
|
82
|
+
|
|
83
|
+
export type AgentHookMatcher = {
|
|
84
|
+
/**
|
|
85
|
+
* Glob over tool names. `'*'` matches every tool. Semantics provider-side
|
|
86
|
+
* but every provider understands `'*'`.
|
|
87
|
+
*/
|
|
88
|
+
matcher: string
|
|
89
|
+
hooks: AgentHookHandler[]
|
|
90
|
+
timeout?: number
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export type AgentHooks = {
|
|
94
|
+
preToolUse?: AgentHookMatcher[]
|
|
95
|
+
postToolUse?: AgentHookMatcher[]
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Context window usage snapshot returned by {@link AgentSession.getContextUsage}.
|
|
100
|
+
* Loose-typed because providers expose different breakdowns; the renderer
|
|
101
|
+
* picks `totalTokens` / `maxTokens` / `percentage` and falls back to the
|
|
102
|
+
* raw bag for advanced UI.
|
|
103
|
+
*/
|
|
104
|
+
export type AgentContextUsage = {
|
|
105
|
+
total?: number
|
|
106
|
+
totalTokens?: number
|
|
107
|
+
maxTokens?: number
|
|
108
|
+
rawMaxTokens?: number
|
|
109
|
+
percentage?: number
|
|
110
|
+
model?: string
|
|
111
|
+
by_category?: Record<string, number>
|
|
112
|
+
[k: string]: unknown
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Listing entry for `~/.claude/projects/<encoded>/<uuid>.jsonl` (or its
|
|
117
|
+
* equivalent under future providers). Loose-typed: providers may expose
|
|
118
|
+
* extra fields that the scanner just passes through.
|
|
119
|
+
*/
|
|
120
|
+
export type AgentSessionInfo = {
|
|
121
|
+
sessionId: string
|
|
122
|
+
cwd?: string
|
|
123
|
+
summary?: string
|
|
124
|
+
customTitle?: string | null
|
|
125
|
+
firstPrompt?: string | null
|
|
126
|
+
lastModified?: number
|
|
127
|
+
createdAt?: number | null
|
|
128
|
+
gitBranch?: string | null
|
|
129
|
+
fileSize?: number
|
|
130
|
+
[k: string]: unknown
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* One turn of input the host pushes onto the prompt queue. Plain text today
|
|
135
|
+
* — providers wrap it into their wire-native user-message envelope. When a
|
|
136
|
+
* future host needs to push richer turns (e.g. images), this can grow into
|
|
137
|
+
* a structured union without breaking the queue contract.
|
|
138
|
+
*/
|
|
139
|
+
export type AgentUserPrompt = string
|
|
140
|
+
|
|
141
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
142
|
+
// Query options & input
|
|
143
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Options the host hands to {@link AgentBackend.query}. All fields are
|
|
147
|
+
* neutral; provider-private extras live behind {@link providerSpawnHints}.
|
|
148
|
+
*/
|
|
149
|
+
export type AgentQueryOptions = {
|
|
150
|
+
cwd?: string
|
|
151
|
+
permissionMode?: AgentPermissionMode
|
|
152
|
+
includePartialMessages?: boolean
|
|
153
|
+
settingSources?: AgentSettingSource[]
|
|
154
|
+
agentProgressSummaries?: boolean
|
|
155
|
+
allowedTools?: string[]
|
|
156
|
+
systemPrompt?: AgentSystemPrompt
|
|
157
|
+
/**
|
|
158
|
+
* Extra working directories beyond `cwd` that the agent can Read/Write
|
|
159
|
+
* across. Populated via `JackProvider.applyKnowledgeContext` from the
|
|
160
|
+
* merged KnowledgeContext (workspace tree + AgentDefinition `kind=dir`
|
|
161
|
+
* knowledge sources).
|
|
162
|
+
*/
|
|
163
|
+
additionalDirectories?: string[]
|
|
164
|
+
mcpServers?: Record<string, AgentMcpServerConfig>
|
|
165
|
+
resume?: string
|
|
166
|
+
/**
|
|
167
|
+
* Initial model for the spawn. Live switches use
|
|
168
|
+
* {@link AgentSession.setModel}.
|
|
169
|
+
*/
|
|
170
|
+
model?: string
|
|
171
|
+
/**
|
|
172
|
+
* Initial effort level for the spawn. Live switches use
|
|
173
|
+
* {@link AgentSession.applyFlagSettings} with `{ effortLevel: ... }`.
|
|
174
|
+
*/
|
|
175
|
+
effort?: AgentEffortLevel
|
|
176
|
+
/**
|
|
177
|
+
* Process spawner — decides how the provider's child process is launched.
|
|
178
|
+
* Defaults to running locally. For sandboxed sessions, the host passes a
|
|
179
|
+
* spawner created by `createDockerSpawner()`.
|
|
180
|
+
*/
|
|
181
|
+
spawner?: ProcessSpawner
|
|
182
|
+
/** Extra env vars merged into the spawned process environment. */
|
|
183
|
+
env?: { [key: string]: string | undefined }
|
|
184
|
+
/**
|
|
185
|
+
* Provider-private spawn details. Populated by
|
|
186
|
+
* `JackProvider.prepareSpawnOptions` and consumed by the matching backend
|
|
187
|
+
* implementation. The host treats this bag as opaque — never read or
|
|
188
|
+
* mutate the inner fields outside the provider package.
|
|
189
|
+
*
|
|
190
|
+
* Today the Claude provider stores `executable` and
|
|
191
|
+
* `pathToClaudeCodeExecutable` here so the SDK backend can locate the
|
|
192
|
+
* asar-unpacked `cli.js` + the macOS Electron Helper.
|
|
193
|
+
*/
|
|
194
|
+
providerSpawnHints?: Record<string, unknown>
|
|
195
|
+
/**
|
|
196
|
+
* Permission gate. Receives a {@link NormalizedPermissionRequest} and
|
|
197
|
+
* resolves to a {@link NormalizedPermissionResult}. Each provider's
|
|
198
|
+
* backend translates between its wire format and these neutral shapes.
|
|
199
|
+
*/
|
|
200
|
+
canUseTool?: (req: NormalizedPermissionRequest) => Promise<NormalizedPermissionResult>
|
|
201
|
+
hooks?: AgentHooks
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export type AgentQueryInput = {
|
|
205
|
+
prompt: AgentUserPrompt | AsyncIterable<AgentUserPrompt>
|
|
206
|
+
options: AgentQueryOptions
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
210
|
+
// Session interface
|
|
211
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Session-like object returned by backend.query(). Mirrors the subset of
|
|
215
|
+
* the provider's runtime control surface that the host actually depends
|
|
216
|
+
* on — intentionally narrow to keep backend implementations small.
|
|
217
|
+
*/
|
|
218
|
+
export interface AgentSession extends AsyncIterable<NormalizedMessage> {
|
|
219
|
+
interrupt(): Promise<void>
|
|
220
|
+
close(): void
|
|
221
|
+
getContextUsage(): Promise<AgentContextUsage>
|
|
222
|
+
stopTask(taskId: string): Promise<void>
|
|
223
|
+
/**
|
|
224
|
+
* Switch permission mode live, without respawning the child process.
|
|
225
|
+
* Mirrors the CLI's Shift+Tab cycle (Claude provider).
|
|
226
|
+
*/
|
|
227
|
+
setPermissionMode(mode: AgentPermissionMode | undefined): Promise<void>
|
|
228
|
+
/**
|
|
229
|
+
* Switch the model live. Pass `undefined` to clear any override and
|
|
230
|
+
* fall back to the provider default.
|
|
231
|
+
*/
|
|
232
|
+
setModel(model?: string): Promise<void>
|
|
233
|
+
/**
|
|
234
|
+
* Merge arbitrary settings into the flag-settings layer at runtime.
|
|
235
|
+
* Used for values the provider exposes only as persisted flags
|
|
236
|
+
* (notably `effortLevel` on Claude).
|
|
237
|
+
*/
|
|
238
|
+
applyFlagSettings(settings: Record<string, unknown>): Promise<void>
|
|
239
|
+
/**
|
|
240
|
+
* Read the effective merged settings layer. The response shape is
|
|
241
|
+
* `{ effective, sources }` where `effective` is the deep-merged result.
|
|
242
|
+
* The host uses it to discover the runtime `effortLevel` the provider
|
|
243
|
+
* booted with.
|
|
244
|
+
*/
|
|
245
|
+
getSettings(): Promise<AgentSettingsResponse>
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Slimmed-down shape of the `get_settings` response. Providers may surface
|
|
250
|
+
* hundreds of fields; we only look at the bits the host cares about and
|
|
251
|
+
* keep the rest opaque.
|
|
252
|
+
*/
|
|
253
|
+
export type AgentSettingsResponse = {
|
|
254
|
+
effective?: { effortLevel?: string; [key: string]: unknown }
|
|
255
|
+
sources?: Record<string, unknown>
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/** Options for backend.listSessions(). */
|
|
259
|
+
export type AgentListSessionsOptions = {
|
|
260
|
+
dir?: string
|
|
261
|
+
limit?: number
|
|
262
|
+
offset?: number
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/** Options for backend.forkSession(). */
|
|
266
|
+
export type AgentForkSessionOptions = {
|
|
267
|
+
dir?: string
|
|
268
|
+
upToMessageId?: string
|
|
269
|
+
title?: string
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
export interface AgentBackend {
|
|
273
|
+
readonly name: BackendName
|
|
274
|
+
query(input: AgentQueryInput): AgentSession
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* List provider sessions on disk. Each backend reads its provider's
|
|
278
|
+
* native transcript layout (`~/.claude/projects/...`,
|
|
279
|
+
* `~/.codex/sessions/...`, `~/.gemini/tmp/.../chats/...`).
|
|
280
|
+
*/
|
|
281
|
+
listSessions(opts?: AgentListSessionsOptions): Promise<AgentSessionInfo[]>
|
|
282
|
+
|
|
283
|
+
/** Persist a custom title for a session. */
|
|
284
|
+
renameSession(sessionId: string, title: string, opts?: { dir?: string }): Promise<void>
|
|
285
|
+
|
|
286
|
+
/** Fork a session into a new one (optionally truncated at a cutoff message). */
|
|
287
|
+
forkSession(
|
|
288
|
+
sessionId: string,
|
|
289
|
+
opts?: AgentForkSessionOptions
|
|
290
|
+
): Promise<{ sessionId: string }>
|
|
291
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@ottimis/jack-provider-sdk` — public surface for AI provider plugins.
|
|
3
|
+
*
|
|
4
|
+
* In-tree providers (Claude, Codex, Gemini) and any future external
|
|
5
|
+
* package import every neutral type + primitive from here. The host
|
|
6
|
+
* imports from here too so a provider package depends only on this SDK
|
|
7
|
+
* (not on Jack's main process internals) and Jack stays free to evolve
|
|
8
|
+
* its host code without breaking provider authors.
|
|
9
|
+
*
|
|
10
|
+
* Re-exports cover three layers:
|
|
11
|
+
* - `./backend` — neutral wire-shape contract (`AgentBackend`,
|
|
12
|
+
* `AgentQueryOptions`, `AgentSession`, …)
|
|
13
|
+
* - `./spawner` — process-spawning primitives shared by every backend
|
|
14
|
+
* (`ProcessSpawner`, `ProcessHandle`, `localSpawner`, …)
|
|
15
|
+
* - `./provider` — plugin-level contract (`JackProvider`,
|
|
16
|
+
* `CapabilityMatrix`, `ToolDescriptor`, `ProviderBranding`, …)
|
|
17
|
+
*
|
|
18
|
+
* Companion runtime types from `@ottimis/jack-chat-core` (`NormalizedMessage`,
|
|
19
|
+
* `ClientToolHandler`, `ToolShape`, …) are re-exported through `./provider`
|
|
20
|
+
* so consumers don't need to import from chat-core directly when they only
|
|
21
|
+
* need the canonical wire shapes.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
export * from './backend'
|
|
25
|
+
export * from './spawner'
|
|
26
|
+
export * from './provider'
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Re-export of `NormalizedMessage` from chat-core so consumers don't need
|
|
30
|
+
* to depend on it directly when their only entrypoint into the wire shape
|
|
31
|
+
* is via `AgentBackend`. Mirrors the legacy
|
|
32
|
+
* `src/main/agent/backend.ts` re-export.
|
|
33
|
+
*/
|
|
34
|
+
export type { NormalizedMessage } from '@ottimis/jack-chat-core'
|