@studio-foundation/contracts 0.3.0-beta.1
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/.claude/settings.json +5 -0
- package/ARCHITECTURE.md +33 -0
- package/LICENSE +663 -0
- package/README.md +106 -0
- package/package.json +33 -0
- package/src/agent.ts +33 -0
- package/src/context-pack.ts +15 -0
- package/src/errors.ts +23 -0
- package/src/index.ts +18 -0
- package/src/integration-plugin.ts +34 -0
- package/src/pipeline.ts +97 -0
- package/src/provider.ts +39 -0
- package/src/run.ts +49 -0
- package/src/runner-events.ts +69 -0
- package/src/spawner.ts +19 -0
- package/src/stage.ts +13 -0
- package/src/task.ts +3 -0
- package/src/tool-plugin.ts +47 -0
- package/src/validation.ts +42 -0
- package/tests/types.test.ts +101 -0
- package/tsconfig.json +24 -0
- package/tsconfig.test.json +8 -0
package/README.md
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# @studio-foundation/contracts
|
|
2
|
+
|
|
3
|
+
Shared TypeScript types and interfaces for the Studio monorepo. Zero dependencies, zero logic.
|
|
4
|
+
|
|
5
|
+
## Role
|
|
6
|
+
|
|
7
|
+
`contracts` is the leaf package — every other Studio package imports from it, nothing imports it back. It defines the language that all packages speak.
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
contracts ← ralph
|
|
11
|
+
contracts ← runner
|
|
12
|
+
contracts ← engine
|
|
13
|
+
contracts ← cli
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## What's in here
|
|
17
|
+
|
|
18
|
+
| Module | Purpose |
|
|
19
|
+
|--------|---------|
|
|
20
|
+
| `pipeline.ts` | `PipelineDefinition`, `StageDefinition`, `StageGroup`, `StageHooks`, `ToolHookDef`, `StageHookDef`, `StartupCommand`, `isStageGroup()` |
|
|
21
|
+
| `stage.ts` | `StageStatus`, `StageKind`, `StageResult` |
|
|
22
|
+
| `task.ts` | `TaskStatus` |
|
|
23
|
+
| `agent.ts` | `AgentConfig`, `AgentProfile`, `ToolCall` (includes `plugins`, `skills`, `anonymize`) |
|
|
24
|
+
| `run.ts` | `PipelineRun`, `StageRun`, `TaskRun`, `AgentRun`, `AgentStatus` |
|
|
25
|
+
| `validation.ts` | `OutputContract`, `ToolCallRequirements`, `ValidationResult`, `ValidationRule` |
|
|
26
|
+
| `provider.ts` | `LLMRequest`, `LLMResponse`, `Message`, `ToolDefinition` |
|
|
27
|
+
| `errors.ts` | `ErrorCode` (enum), `StudioError` |
|
|
28
|
+
| `context-pack.ts` | `ContextPackDefinition`, `ResolvedContextPack` |
|
|
29
|
+
| `tool-plugin.ts` | `ToolPluginDef`, `ToolCommandDef`, `ShellExecute`, `BuiltinExecute`, `ParameterDef` |
|
|
30
|
+
| `runner-events.ts` | `RunnerCallbacks`, `ToolCallStartEvent`, `ToolCallCompleteEvent`, `AgentThinkingEvent`, `AgentProgressEvent`, `AgentTokenEvent` |
|
|
31
|
+
| `spawner.ts` | `RunSpawner`, `SpawnConfig`, `SpawnResult` |
|
|
32
|
+
| `integration-plugin.ts` | `IntegrationPluginDef` |
|
|
33
|
+
|
|
34
|
+
## Key types
|
|
35
|
+
|
|
36
|
+
### Hooks (pipeline.ts)
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
// Stage-level hook (on_stage_start, on_stage_complete)
|
|
40
|
+
interface StageHookDef {
|
|
41
|
+
command: string;
|
|
42
|
+
on_failure?: 'warn' | 'reject' | 'fail'; // default: 'warn'
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Tool-level hook (pre_tool_use, post_tool_use)
|
|
46
|
+
interface ToolHookDef {
|
|
47
|
+
matcher: string; // exact tool name, e.g. "repo_manager-write_file"
|
|
48
|
+
command: string;
|
|
49
|
+
on_failure?: 'warn' | 'reject';
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
interface StageHooks {
|
|
53
|
+
on_stage_start?: StageHookDef[];
|
|
54
|
+
on_stage_complete?: StageHookDef[];
|
|
55
|
+
pre_tool_use?: ToolHookDef[];
|
|
56
|
+
post_tool_use?: ToolHookDef[];
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Agent (agent.ts)
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
interface AgentConfig {
|
|
64
|
+
name: string;
|
|
65
|
+
provider: string;
|
|
66
|
+
model: string;
|
|
67
|
+
system_prompt?: string;
|
|
68
|
+
tools?: string[];
|
|
69
|
+
plugins?: string[]; // Claude Code plugin names
|
|
70
|
+
skills?: string[]; // .skill.md file names
|
|
71
|
+
anonymize?: boolean; // Enable PII anonymization
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### on_pipeline_start (pipeline.ts)
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
interface StartupCommand {
|
|
79
|
+
command: string; // Shell command to run
|
|
80
|
+
inject_as: string; // Key to inject stdout under
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Sub-pipeline spawning (spawner.ts)
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
interface RunSpawner {
|
|
88
|
+
spawnAndWait(config: SpawnConfig): Promise<SpawnResult>;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
interface SpawnConfig {
|
|
92
|
+
pipeline: string;
|
|
93
|
+
input: Record<string, unknown>;
|
|
94
|
+
parentRunId: string;
|
|
95
|
+
depth: number;
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Used by the `studio_run` builtin tool to spawn sub-pipelines from within an agent run.
|
|
100
|
+
|
|
101
|
+
## Rules
|
|
102
|
+
|
|
103
|
+
- **Zero dependencies** — no imports from other `@studio/*` packages, ever.
|
|
104
|
+
- **Zero logic** — types and interfaces only. The one exception: `isStageGroup()` in `pipeline.ts` is a pure type guard function (no side effects, no state).
|
|
105
|
+
- If you need to add a type used by two packages, put it here.
|
|
106
|
+
- If you're adding logic, you're in the wrong package.
|
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@studio-foundation/contracts",
|
|
3
|
+
"version": "0.3.0-beta.1",
|
|
4
|
+
"description": "Shared TypeScript types and interfaces for Studio v7",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"keywords": [
|
|
15
|
+
"studio",
|
|
16
|
+
"types",
|
|
17
|
+
"contracts"
|
|
18
|
+
],
|
|
19
|
+
"author": "Ariane Guay",
|
|
20
|
+
"license": "AGPL-3.0-only",
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"typescript": "^5.3.0",
|
|
23
|
+
"vitest": "^4.0.18"
|
|
24
|
+
},
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "tsc",
|
|
27
|
+
"dev": "tsc --watch",
|
|
28
|
+
"clean": "rm -rf dist",
|
|
29
|
+
"typecheck": "tsc --noEmit",
|
|
30
|
+
"test": "vitest run",
|
|
31
|
+
"test:watch": "vitest"
|
|
32
|
+
}
|
|
33
|
+
}
|
package/src/agent.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// Agent configuration and profiles
|
|
2
|
+
|
|
3
|
+
export interface AgentConfig {
|
|
4
|
+
name: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
provider?: string;
|
|
7
|
+
model?: string;
|
|
8
|
+
system_prompt?: string;
|
|
9
|
+
tools?: string[];
|
|
10
|
+
plugins?: string[];
|
|
11
|
+
skills?: string[];
|
|
12
|
+
temperature?: number;
|
|
13
|
+
max_tokens?: number;
|
|
14
|
+
anonymize?: boolean; // Enable PII anonymization for this agent
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** AgentConfig after defaults have been applied — provider and model are guaranteed. */
|
|
18
|
+
export interface ResolvedAgentConfig extends AgentConfig {
|
|
19
|
+
provider: string;
|
|
20
|
+
model: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface AgentProfile extends AgentConfig {
|
|
24
|
+
// Additional profile-specific fields
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface ToolCall {
|
|
28
|
+
id: string;
|
|
29
|
+
name: string;
|
|
30
|
+
arguments: Record<string, unknown>;
|
|
31
|
+
result?: unknown;
|
|
32
|
+
error?: string;
|
|
33
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// Shared types for the context packs feature (STU-13)
|
|
2
|
+
|
|
3
|
+
export interface ContextPackDefinition {
|
|
4
|
+
name: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
version: number;
|
|
7
|
+
files?: Array<{ path: string }>;
|
|
8
|
+
inline?: Array<{ title: string; content: string }>;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface ResolvedContextPack {
|
|
12
|
+
name: string;
|
|
13
|
+
description?: string;
|
|
14
|
+
sections: Array<{ title: string; content: string }>;
|
|
15
|
+
}
|
package/src/errors.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// Error types and codes
|
|
2
|
+
|
|
3
|
+
export enum ErrorCode {
|
|
4
|
+
VALIDATION_FAILED = 'VALIDATION_FAILED',
|
|
5
|
+
AGENT_EXECUTION_FAILED = 'AGENT_EXECUTION_FAILED',
|
|
6
|
+
STAGE_FAILED = 'STAGE_FAILED',
|
|
7
|
+
PIPELINE_FAILED = 'PIPELINE_FAILED',
|
|
8
|
+
RALPH_EXHAUSTED = 'RALPH_EXHAUSTED',
|
|
9
|
+
TOOL_EXECUTION_FAILED = 'TOOL_EXECUTION_FAILED',
|
|
10
|
+
PROVIDER_ERROR = 'PROVIDER_ERROR',
|
|
11
|
+
CONFIGURATION_ERROR = 'CONFIGURATION_ERROR',
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export class StudioError extends Error {
|
|
15
|
+
constructor(
|
|
16
|
+
public code: ErrorCode,
|
|
17
|
+
message: string,
|
|
18
|
+
public details?: Record<string, unknown>
|
|
19
|
+
) {
|
|
20
|
+
super(message);
|
|
21
|
+
this.name = 'StudioError';
|
|
22
|
+
}
|
|
23
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// Export barrel for @studio/contracts
|
|
2
|
+
// All types are re-exported from their source files
|
|
3
|
+
|
|
4
|
+
export * from './pipeline.js';
|
|
5
|
+
export * from './stage.js';
|
|
6
|
+
export * from './task.js';
|
|
7
|
+
export * from './agent.js';
|
|
8
|
+
export * from './run.js';
|
|
9
|
+
export * from './validation.js';
|
|
10
|
+
export * from './provider.js';
|
|
11
|
+
export * from './errors.js';
|
|
12
|
+
export * from './context-pack.js';
|
|
13
|
+
export * from './tool-plugin.js';
|
|
14
|
+
|
|
15
|
+
export * from './runner-events.js';
|
|
16
|
+
|
|
17
|
+
export * from './spawner.js';
|
|
18
|
+
export * from './integration-plugin.js';
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// contracts/src/integration-plugin.ts
|
|
2
|
+
|
|
3
|
+
export interface IntegrationPluginDef {
|
|
4
|
+
name: string;
|
|
5
|
+
version: number;
|
|
6
|
+
description?: string;
|
|
7
|
+
config?: {
|
|
8
|
+
required?: string[];
|
|
9
|
+
optional?: Record<string, unknown>;
|
|
10
|
+
};
|
|
11
|
+
events?: {
|
|
12
|
+
consumes?: string[];
|
|
13
|
+
emits?: string[];
|
|
14
|
+
};
|
|
15
|
+
test?: {
|
|
16
|
+
type: 'http';
|
|
17
|
+
endpoint: string;
|
|
18
|
+
method?: 'GET' | 'POST';
|
|
19
|
+
/** e.g. "bearer:${LINEAR_API_KEY}" — resolved before use */
|
|
20
|
+
auth?: string;
|
|
21
|
+
body?: string;
|
|
22
|
+
expect?: { status?: number };
|
|
23
|
+
};
|
|
24
|
+
webhook?: {
|
|
25
|
+
hmac?: {
|
|
26
|
+
header: string; // e.g. 'linear-signature'
|
|
27
|
+
secret_env: string; // e.g. 'LINEAR_WEBHOOK_SECRET' — resolved from integration config
|
|
28
|
+
};
|
|
29
|
+
handler: string; // e.g. 'linear-webhook' — key in WEBHOOK_HANDLERS registry
|
|
30
|
+
};
|
|
31
|
+
on_failure?: {
|
|
32
|
+
handler: string; // e.g. 'linear-failure' — key in FAILURE_HANDLERS registry
|
|
33
|
+
};
|
|
34
|
+
}
|
package/src/pipeline.ts
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
// Pipeline and Stage definitions
|
|
2
|
+
|
|
3
|
+
import type { StageKind } from './stage';
|
|
4
|
+
|
|
5
|
+
export interface InputField {
|
|
6
|
+
name: string;
|
|
7
|
+
type: 'text' | 'array';
|
|
8
|
+
prompt: string;
|
|
9
|
+
required: boolean;
|
|
10
|
+
default?: string;
|
|
11
|
+
items?: 'text';
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface InputSchema {
|
|
15
|
+
type: 'structured';
|
|
16
|
+
fields: InputField[];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface StartupCommand {
|
|
20
|
+
command: string;
|
|
21
|
+
inject_as: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface PipelineDefinition {
|
|
25
|
+
name: string;
|
|
26
|
+
description: string;
|
|
27
|
+
version: number;
|
|
28
|
+
on_pipeline_start?: StartupCommand[];
|
|
29
|
+
input_schema?: InputSchema;
|
|
30
|
+
repo?: {
|
|
31
|
+
url: string;
|
|
32
|
+
branch?: string;
|
|
33
|
+
};
|
|
34
|
+
stages: PipelineEntry[];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Lifecycle hooks — configurable shell commands at stage/tool lifecycle points
|
|
38
|
+
|
|
39
|
+
export type HookOnFailure = 'warn' | 'reject' | 'fail';
|
|
40
|
+
|
|
41
|
+
export interface StageHookDef {
|
|
42
|
+
command: string;
|
|
43
|
+
on_failure?: HookOnFailure; // default: 'warn'
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface ToolHookDef {
|
|
47
|
+
matcher: string; // exact tool name to match (e.g. "repo_manager-write_file")
|
|
48
|
+
command: string;
|
|
49
|
+
on_failure?: 'warn' | 'reject'; // default: 'warn' — 'fail' not supported at tool boundary
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface StageHooks {
|
|
53
|
+
on_stage_start?: StageHookDef[];
|
|
54
|
+
on_stage_complete?: StageHookDef[];
|
|
55
|
+
pre_tool_use?: ToolHookDef[];
|
|
56
|
+
post_tool_use?: ToolHookDef[];
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface StageDefinition {
|
|
60
|
+
name: string;
|
|
61
|
+
condition?: string; // e.g. "input.meals_count >= 6" or "stages.foo.output.count > 0"
|
|
62
|
+
kind?: StageKind;
|
|
63
|
+
agent?: string; // optional — not needed for script executor
|
|
64
|
+
executor?: 'script'; // 'script' or absent (defaults to LLM)
|
|
65
|
+
script?: string; // path to script file (required when executor: 'script')
|
|
66
|
+
runtime?: 'python' | 'node' | 'shell'; // runtime for script executor
|
|
67
|
+
timeout_ms?: number; // script timeout in ms (default: 30000)
|
|
68
|
+
contract?: string;
|
|
69
|
+
ralph?: {
|
|
70
|
+
max_attempts: number;
|
|
71
|
+
retry_strategy: string;
|
|
72
|
+
max_tool_calls?: number;
|
|
73
|
+
};
|
|
74
|
+
context?: {
|
|
75
|
+
include: string[];
|
|
76
|
+
packs?: string[];
|
|
77
|
+
};
|
|
78
|
+
tools?: {
|
|
79
|
+
required?: string[];
|
|
80
|
+
};
|
|
81
|
+
hooks?: StageHooks;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// A pipeline entry is either a stage or a group of stages
|
|
85
|
+
export type PipelineEntry = StageDefinition | StageGroup;
|
|
86
|
+
|
|
87
|
+
export interface StageGroup {
|
|
88
|
+
group: string;
|
|
89
|
+
max_iterations: number;
|
|
90
|
+
mode?: 'sequential' | 'parallel'; // default: 'sequential'
|
|
91
|
+
on_failure?: 'fail-fast' | 'collect-all'; // parallel only, default: 'fail-fast'
|
|
92
|
+
stages: StageDefinition[];
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export function isStageGroup(entry: PipelineEntry): entry is StageGroup {
|
|
96
|
+
return 'group' in entry && 'stages' in entry;
|
|
97
|
+
}
|
package/src/provider.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// LLM provider interfaces
|
|
2
|
+
|
|
3
|
+
export interface LLMRequest {
|
|
4
|
+
model: string;
|
|
5
|
+
messages: Message[];
|
|
6
|
+
tools?: ToolDefinition[];
|
|
7
|
+
temperature?: number;
|
|
8
|
+
max_tokens?: number;
|
|
9
|
+
stage_name?: string;
|
|
10
|
+
json_mode?: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface Message {
|
|
14
|
+
role: 'system' | 'user' | 'assistant';
|
|
15
|
+
content: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface LLMResponse {
|
|
19
|
+
content: string;
|
|
20
|
+
tool_calls?: Array<{
|
|
21
|
+
id: string;
|
|
22
|
+
name: string;
|
|
23
|
+
arguments: Record<string, unknown>;
|
|
24
|
+
}>;
|
|
25
|
+
finish_reason: string;
|
|
26
|
+
usage?: {
|
|
27
|
+
prompt_tokens: number;
|
|
28
|
+
completion_tokens: number;
|
|
29
|
+
total_tokens: number;
|
|
30
|
+
cached_input_tokens?: number;
|
|
31
|
+
cache_creation_tokens?: number;
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface ToolDefinition {
|
|
36
|
+
name: string;
|
|
37
|
+
description: string;
|
|
38
|
+
parameters: Record<string, unknown>;
|
|
39
|
+
}
|
package/src/run.ts
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// Runtime execution tracking
|
|
2
|
+
|
|
3
|
+
import type { StageStatus } from './stage';
|
|
4
|
+
import type { TaskStatus } from './task';
|
|
5
|
+
|
|
6
|
+
export type AgentStatus = 'pending' | 'running' | 'success' | 'failed';
|
|
7
|
+
|
|
8
|
+
export interface PipelineRun {
|
|
9
|
+
id: string;
|
|
10
|
+
pipeline_name: string;
|
|
11
|
+
status: StageStatus;
|
|
12
|
+
started_at: string;
|
|
13
|
+
completed_at?: string;
|
|
14
|
+
stages: StageRun[];
|
|
15
|
+
input?: Record<string, unknown>;
|
|
16
|
+
parent_run_id?: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface StageRun {
|
|
20
|
+
id: string;
|
|
21
|
+
stage_name: string;
|
|
22
|
+
status: StageStatus;
|
|
23
|
+
started_at: string;
|
|
24
|
+
completed_at?: string;
|
|
25
|
+
tasks: TaskRun[];
|
|
26
|
+
output?: unknown; // final output of the stage (populated by engine for observability)
|
|
27
|
+
skipped_reason?: string; // reason why stage was skipped (populated by resume loop)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface TaskRun {
|
|
31
|
+
id: string;
|
|
32
|
+
task_name: string;
|
|
33
|
+
status: TaskStatus;
|
|
34
|
+
started_at: string;
|
|
35
|
+
completed_at?: string;
|
|
36
|
+
agent_runs: AgentRun[];
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface AgentRun {
|
|
40
|
+
id: string;
|
|
41
|
+
agent_name: string;
|
|
42
|
+
attempt: number;
|
|
43
|
+
status: AgentStatus;
|
|
44
|
+
tool_calls: number;
|
|
45
|
+
started_at: string;
|
|
46
|
+
completed_at?: string;
|
|
47
|
+
output?: unknown;
|
|
48
|
+
error?: string;
|
|
49
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Event types for real-time tool call streaming.
|
|
3
|
+
* Defined in contracts (leaf package) so runner can import them
|
|
4
|
+
* without creating an inverse dependency on engine.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export interface ToolCallStartEvent {
|
|
8
|
+
tool: string;
|
|
9
|
+
params: Record<string, unknown>;
|
|
10
|
+
timestamp: number; // ms since epoch (Date.now())
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface ToolCallCompleteEvent {
|
|
14
|
+
tool: string;
|
|
15
|
+
result: unknown; // tool-plugin-specific; typed by each tool plugin
|
|
16
|
+
error?: string;
|
|
17
|
+
duration_ms: number;
|
|
18
|
+
timestamp: number; // ms since epoch (Date.now())
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface AgentThinkingEvent {
|
|
22
|
+
thought: string; // LLM text content emitted before the first round of tool calls
|
|
23
|
+
timestamp: number; // ms since epoch (Date.now())
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface AgentProgressEvent {
|
|
27
|
+
message: string; // LLM text content emitted between subsequent rounds of tool calls
|
|
28
|
+
timestamp: number; // ms since epoch (Date.now())
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface AgentTokenEvent {
|
|
32
|
+
token: string;
|
|
33
|
+
timestamp: number; // ms since epoch (Date.now())
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Subset of callbacks the runner accepts for real-time event emission.
|
|
38
|
+
* Engine populates these from EngineEvents and passes them to runAgent().
|
|
39
|
+
*/
|
|
40
|
+
export interface RunnerCallbacks {
|
|
41
|
+
onToolCallStart?: (event: ToolCallStartEvent) => void;
|
|
42
|
+
onToolCallComplete?: (event: ToolCallCompleteEvent) => void;
|
|
43
|
+
onAgentThinking?: (event: AgentThinkingEvent) => void;
|
|
44
|
+
onAgentProgress?: (event: AgentProgressEvent) => void;
|
|
45
|
+
onAgentToken?: (event: AgentTokenEvent) => void;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Called before tool execution. Return { blocked: true, error } to prevent the tool from running.
|
|
49
|
+
* The error is surfaced as the tool result so the LLM can react and RALPH loop continues.
|
|
50
|
+
*/
|
|
51
|
+
onPreToolUse?: (event: {
|
|
52
|
+
tool: string;
|
|
53
|
+
params: Record<string, unknown>;
|
|
54
|
+
timestamp: number;
|
|
55
|
+
}) => Promise<{ blocked: boolean; error?: string }>;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Called after tool execution (only if the tool was not blocked).
|
|
59
|
+
* Return { append_message } to inject a note into the conversation after the tool result.
|
|
60
|
+
* Only effective in the standard (Chat Completions) provider path.
|
|
61
|
+
*/
|
|
62
|
+
onPostToolUse?: (event: {
|
|
63
|
+
tool: string;
|
|
64
|
+
params: Record<string, unknown>;
|
|
65
|
+
result: unknown;
|
|
66
|
+
error?: string;
|
|
67
|
+
timestamp: number;
|
|
68
|
+
}) => Promise<{ append_message?: string }>;
|
|
69
|
+
}
|
package/src/spawner.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// The abstraction that studio-run tool uses to launch child runs.
|
|
2
|
+
// Implementations: DirectEngineSpawner (engine) and HttpApiSpawner (api).
|
|
3
|
+
|
|
4
|
+
export interface SpawnConfig {
|
|
5
|
+
pipeline: string;
|
|
6
|
+
input: Record<string, unknown>;
|
|
7
|
+
parentRunId: string;
|
|
8
|
+
depth: number;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface SpawnResult {
|
|
12
|
+
run_id: string;
|
|
13
|
+
status: string;
|
|
14
|
+
output: unknown;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface RunSpawner {
|
|
18
|
+
spawnAndWait(config: SpawnConfig): Promise<SpawnResult>;
|
|
19
|
+
}
|
package/src/stage.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// Stage status and results
|
|
2
|
+
|
|
3
|
+
export type StageStatus = 'pending' | 'running' | 'success' | 'failed' | 'skipped' | 'rejected' | 'cancelled';
|
|
4
|
+
|
|
5
|
+
export type StageKind = string;
|
|
6
|
+
|
|
7
|
+
export interface StageResult {
|
|
8
|
+
status: StageStatus;
|
|
9
|
+
output?: unknown;
|
|
10
|
+
error?: string;
|
|
11
|
+
attempts: number;
|
|
12
|
+
duration_ms: number;
|
|
13
|
+
}
|
package/src/task.ts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// contracts/src/tool-plugin.ts
|
|
2
|
+
|
|
3
|
+
export type ParseOutputFormat = 'text' | 'json';
|
|
4
|
+
|
|
5
|
+
export interface ParameterDef {
|
|
6
|
+
type: 'string' | 'number' | 'boolean' | 'array';
|
|
7
|
+
description?: string;
|
|
8
|
+
required?: boolean;
|
|
9
|
+
default?: unknown;
|
|
10
|
+
items?: { type: string };
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface ShellExecute {
|
|
14
|
+
type: 'shell';
|
|
15
|
+
command: string;
|
|
16
|
+
parse_output?: ParseOutputFormat;
|
|
17
|
+
timeout_ms?: number;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface BuiltinExecute {
|
|
21
|
+
type: 'builtin';
|
|
22
|
+
handler?: string; // informational only — we look up by cmd.name
|
|
23
|
+
parse_output?: ParseOutputFormat;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export type CommandExecute = ShellExecute | BuiltinExecute;
|
|
27
|
+
|
|
28
|
+
export interface ToolCommandDef {
|
|
29
|
+
name: string;
|
|
30
|
+
description: string;
|
|
31
|
+
parameters: Record<string, ParameterDef>;
|
|
32
|
+
execute: CommandExecute;
|
|
33
|
+
constraints?: Record<string, unknown>;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface ToolPluginDef {
|
|
37
|
+
name: string;
|
|
38
|
+
description?: string;
|
|
39
|
+
version: number;
|
|
40
|
+
commands: ToolCommandDef[];
|
|
41
|
+
config?: Record<string, unknown>;
|
|
42
|
+
prompt_snippet?: string;
|
|
43
|
+
constraints?: {
|
|
44
|
+
requires_initialized_repo?: boolean;
|
|
45
|
+
requires_binaries?: string[];
|
|
46
|
+
};
|
|
47
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// Validation contracts and results
|
|
2
|
+
|
|
3
|
+
export interface ToolCallRequirements {
|
|
4
|
+
minimum?: number;
|
|
5
|
+
maximum?: number;
|
|
6
|
+
required_tools?: string[];
|
|
7
|
+
required_tool_groups?: string[][];
|
|
8
|
+
counted_tools?: string[];
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface OutputContract {
|
|
12
|
+
name: string;
|
|
13
|
+
version: number;
|
|
14
|
+
schema?: {
|
|
15
|
+
required_fields?: string[];
|
|
16
|
+
[key: string]: unknown;
|
|
17
|
+
};
|
|
18
|
+
tool_calls?: ToolCallRequirements;
|
|
19
|
+
custom_rules?: ValidationRule[];
|
|
20
|
+
post_validation?: {
|
|
21
|
+
rejection_detection: {
|
|
22
|
+
field: string;
|
|
23
|
+
rejected_values?: string[];
|
|
24
|
+
approved_values?: string[];
|
|
25
|
+
details_field?: string;
|
|
26
|
+
summary_field?: string;
|
|
27
|
+
reject_if_non_empty?: string;
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface ValidationRule {
|
|
33
|
+
name: string;
|
|
34
|
+
description: string;
|
|
35
|
+
check: string;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface ValidationResult {
|
|
39
|
+
valid: boolean;
|
|
40
|
+
errors: string[];
|
|
41
|
+
warnings: string[];
|
|
42
|
+
}
|