@steerable/agent-harness 0.2.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/LICENSE +91 -0
- package/dist/budget.d.ts +19 -0
- package/dist/budget.js +11 -0
- package/dist/completion.d.ts +1 -0
- package/dist/completion.js +9 -0
- package/dist/generated/AgentSession.d.ts +49 -0
- package/dist/generated/AgentSession.js +1 -0
- package/dist/generated/ChatAgent.d.ts +18 -0
- package/dist/generated/ChatAgent.js +1 -0
- package/dist/generated/ChatMessage.d.ts +14 -0
- package/dist/generated/ChatMessage.js +1 -0
- package/dist/generated/CommandSafetyPattern.d.ts +9 -0
- package/dist/generated/CommandSafetyPattern.js +1 -0
- package/dist/generated/HarnessTrace.d.ts +33 -0
- package/dist/generated/HarnessTrace.js +1 -0
- package/dist/generated/SSEEvent.d.ts +15 -0
- package/dist/generated/SSEEvent.js +1 -0
- package/dist/generated/SidecarError.d.ts +20 -0
- package/dist/generated/SidecarError.js +1 -0
- package/dist/generated/SidecarHealth.d.ts +37 -0
- package/dist/generated/SidecarHealth.js +1 -0
- package/dist/generated/SidecarNotification.d.ts +13 -0
- package/dist/generated/SidecarNotification.js +1 -0
- package/dist/generated/SidecarRequest.d.ts +20 -0
- package/dist/generated/SidecarRequest.js +1 -0
- package/dist/generated/SidecarResponse.d.ts +15 -0
- package/dist/generated/SidecarResponse.js +1 -0
- package/dist/generated/ToolCall.d.ts +7 -0
- package/dist/generated/ToolCall.js +1 -0
- package/dist/generated/ToolResult.d.ts +12 -0
- package/dist/generated/ToolResult.js +1 -0
- package/dist/generated/TraceEvent.d.ts +38 -0
- package/dist/generated/TraceEvent.js +1 -0
- package/dist/generated/TraceSpan.d.ts +38 -0
- package/dist/generated/TraceSpan.js +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +6 -0
- package/dist/policy.d.ts +7 -0
- package/dist/policy.js +20 -0
- package/dist/retry.d.ts +7 -0
- package/dist/retry.js +7 -0
- package/dist/safety-patterns.d.ts +16 -0
- package/dist/safety-patterns.js +71 -0
- package/dist/tracing.d.ts +9 -0
- package/dist/tracing.js +14 -0
- package/package.json +49 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
6
|
+
|
|
7
|
+
1. Definitions.
|
|
8
|
+
|
|
9
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
10
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
11
|
+
|
|
12
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
13
|
+
the copyright owner that is granting the License.
|
|
14
|
+
|
|
15
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
16
|
+
other entities that control, are controlled by, or are under common
|
|
17
|
+
control with that entity.
|
|
18
|
+
|
|
19
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
20
|
+
exercising permissions granted by this License.
|
|
21
|
+
|
|
22
|
+
"Source" form shall mean the preferred form for making modifications.
|
|
23
|
+
|
|
24
|
+
"Object" form shall mean any form resulting from mechanical
|
|
25
|
+
transformation or translation of a Source form.
|
|
26
|
+
|
|
27
|
+
"Work" shall mean the work of authorship made available under the
|
|
28
|
+
License.
|
|
29
|
+
|
|
30
|
+
"Derivative Works" shall mean any work based on the Work.
|
|
31
|
+
|
|
32
|
+
"Contribution" shall mean any work of authorship intentionally
|
|
33
|
+
submitted to Licensor for inclusion in the Work.
|
|
34
|
+
|
|
35
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
36
|
+
on behalf of whom a Contribution has been received by Licensor.
|
|
37
|
+
|
|
38
|
+
2. Grant of Copyright License.
|
|
39
|
+
Subject to the terms and conditions of this License, each Contributor
|
|
40
|
+
hereby grants to You a perpetual, worldwide, non-exclusive, no-charge,
|
|
41
|
+
royalty-free, irrevocable copyright license to reproduce, prepare
|
|
42
|
+
Derivative Works of, publicly display, publicly perform, sublicense,
|
|
43
|
+
and distribute the Work and such Derivative Works in Source or Object
|
|
44
|
+
form.
|
|
45
|
+
|
|
46
|
+
3. Grant of Patent License.
|
|
47
|
+
Subject to the terms and conditions of this License, each Contributor
|
|
48
|
+
hereby grants to You a perpetual, worldwide, non-exclusive, no-charge,
|
|
49
|
+
royalty-free, irrevocable patent license to make, have made, use,
|
|
50
|
+
offer to sell, sell, import, and otherwise transfer the Work.
|
|
51
|
+
|
|
52
|
+
4. Redistribution.
|
|
53
|
+
You may reproduce and distribute copies of the Work or Derivative
|
|
54
|
+
Works thereof in any medium, with or without modifications, and in
|
|
55
|
+
Source or Object form, provided that You meet the following conditions:
|
|
56
|
+
|
|
57
|
+
(a) You must give any other recipients of the Work or Derivative
|
|
58
|
+
Works a copy of this License; and
|
|
59
|
+
(b) You must cause any modified files to carry prominent notices
|
|
60
|
+
stating that You changed the files; and
|
|
61
|
+
(c) You must retain, in the Source form of any Derivative Works that
|
|
62
|
+
You distribute, all copyright, patent, trademark, and attribution
|
|
63
|
+
notices from the Source form of the Work; and
|
|
64
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
65
|
+
distribution, then any Derivative Works that You distribute must
|
|
66
|
+
include a readable copy of the attribution notices contained within
|
|
67
|
+
such NOTICE file.
|
|
68
|
+
|
|
69
|
+
5. Submission of Contributions.
|
|
70
|
+
Unless You explicitly state otherwise, any Contribution intentionally
|
|
71
|
+
submitted for inclusion in the Work shall be under the terms and
|
|
72
|
+
conditions of this License.
|
|
73
|
+
|
|
74
|
+
6. Trademarks.
|
|
75
|
+
This License does not grant permission to use the trade names,
|
|
76
|
+
trademarks, service marks, or product names of the Licensor.
|
|
77
|
+
|
|
78
|
+
7. Disclaimer of Warranty.
|
|
79
|
+
Unless required by applicable law or agreed to in writing, Licensor
|
|
80
|
+
provides the Work on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
|
|
81
|
+
OF ANY KIND.
|
|
82
|
+
|
|
83
|
+
8. Limitation of Liability.
|
|
84
|
+
In no event and under no legal theory shall any Contributor be liable
|
|
85
|
+
to You for damages arising as a result of this License or out of the
|
|
86
|
+
use or inability to use the Work.
|
|
87
|
+
|
|
88
|
+
9. Accepting Warranty or Additional Liability.
|
|
89
|
+
While redistributing the Work or Derivative Works thereof, You may
|
|
90
|
+
choose to offer, and charge a fee for, acceptance of support, warranty,
|
|
91
|
+
indemnity, or other liability obligations.
|
package/dist/budget.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface BudgetLimit {
|
|
2
|
+
maxTokens: number;
|
|
3
|
+
maxSteps: number;
|
|
4
|
+
maxToolCalls: number;
|
|
5
|
+
}
|
|
6
|
+
export interface BudgetState {
|
|
7
|
+
tokensUsed: number;
|
|
8
|
+
stepsUsed: number;
|
|
9
|
+
toolCallsUsed: number;
|
|
10
|
+
}
|
|
11
|
+
export interface BudgetConsumeOptions {
|
|
12
|
+
tokens?: number;
|
|
13
|
+
step?: boolean;
|
|
14
|
+
toolCall?: boolean;
|
|
15
|
+
}
|
|
16
|
+
export declare function consumeBudget(state: BudgetState, limits: BudgetLimit, options?: BudgetConsumeOptions): {
|
|
17
|
+
state: BudgetState;
|
|
18
|
+
exhausted: boolean;
|
|
19
|
+
};
|
package/dist/budget.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export function consumeBudget(state, limits, options = {}) {
|
|
2
|
+
const nextState = {
|
|
3
|
+
tokensUsed: state.tokensUsed + Math.max(options.tokens ?? 0, 0),
|
|
4
|
+
stepsUsed: state.stepsUsed + (options.step ? 1 : 0),
|
|
5
|
+
toolCallsUsed: state.toolCallsUsed + (options.toolCall ? 1 : 0),
|
|
6
|
+
};
|
|
7
|
+
const exhausted = nextState.tokensUsed > limits.maxTokens ||
|
|
8
|
+
nextState.stepsUsed > limits.maxSteps ||
|
|
9
|
+
nextState.toolCallsUsed > limits.maxToolCalls;
|
|
10
|
+
return { state: nextState, exhausted };
|
|
11
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function isTerminalResult(result: Record<string, unknown> | null | undefined): boolean;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A persistent agent execution session. One session corresponds to a single chat-thread/agent-stage finite-state-machine instance.
|
|
3
|
+
*/
|
|
4
|
+
export interface AgentSession {
|
|
5
|
+
/**
|
|
6
|
+
* Internal primary key (cuid). Optional in transit; generated by storage layer if omitted.
|
|
7
|
+
*/
|
|
8
|
+
id?: string;
|
|
9
|
+
/**
|
|
10
|
+
* Globally unique session identifier (visible to clients and used for resume).
|
|
11
|
+
*/
|
|
12
|
+
sessionId: string;
|
|
13
|
+
/**
|
|
14
|
+
* Owner user id.
|
|
15
|
+
*/
|
|
16
|
+
userId: string;
|
|
17
|
+
/**
|
|
18
|
+
* Optional owning project id.
|
|
19
|
+
*/
|
|
20
|
+
projectId?: string | null;
|
|
21
|
+
/**
|
|
22
|
+
* The chat thread this session is bound to. One chat may host multiple sequential sessions.
|
|
23
|
+
*/
|
|
24
|
+
chatId: string;
|
|
25
|
+
/**
|
|
26
|
+
* Current FSM stage name (e.g. 'plan', 'execute', 'review').
|
|
27
|
+
*/
|
|
28
|
+
currentStage: string;
|
|
29
|
+
/**
|
|
30
|
+
* Pre-computed next stage hint, may be overridden by policy.
|
|
31
|
+
*/
|
|
32
|
+
nextStage?: string | null;
|
|
33
|
+
/**
|
|
34
|
+
* Scenario tag used to select the FSM definition (e.g. 'agent-entry', 'cflog-operator').
|
|
35
|
+
*/
|
|
36
|
+
scenario?: string;
|
|
37
|
+
/**
|
|
38
|
+
* Free-form per-stage state bag. Should remain JSON-serializable.
|
|
39
|
+
*/
|
|
40
|
+
stageData?: {
|
|
41
|
+
[k: string]: any;
|
|
42
|
+
} | null;
|
|
43
|
+
/**
|
|
44
|
+
* Whether the session is still accepting new turns.
|
|
45
|
+
*/
|
|
46
|
+
isActive: boolean;
|
|
47
|
+
createdAt: string;
|
|
48
|
+
updatedAt: string;
|
|
49
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface ChatAgent {
|
|
2
|
+
id: string;
|
|
3
|
+
slug?: string;
|
|
4
|
+
name: string;
|
|
5
|
+
icon?: string;
|
|
6
|
+
color?: string;
|
|
7
|
+
description?: string;
|
|
8
|
+
rolePrompt?: string;
|
|
9
|
+
forbiddenPrompt?: string;
|
|
10
|
+
skillIds?: string[];
|
|
11
|
+
allowExternalSkills?: boolean;
|
|
12
|
+
isBuiltin?: boolean;
|
|
13
|
+
isArchived?: boolean;
|
|
14
|
+
sortOrder?: number;
|
|
15
|
+
createdAt: string;
|
|
16
|
+
updatedAt: string;
|
|
17
|
+
[k: string]: any;
|
|
18
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ToolCall } from "./ToolCall.js";
|
|
2
|
+
import type { ToolResult } from "./ToolResult.js";
|
|
3
|
+
export interface ChatMessage {
|
|
4
|
+
id: string;
|
|
5
|
+
chatId?: string;
|
|
6
|
+
role: "user" | "assistant" | "tool" | "system";
|
|
7
|
+
content: string;
|
|
8
|
+
agentId?: string;
|
|
9
|
+
toolCalls?: ToolCall[];
|
|
10
|
+
toolResult?: ToolResult;
|
|
11
|
+
createdAt: string;
|
|
12
|
+
updatedAt?: string;
|
|
13
|
+
[k: string]: any;
|
|
14
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Run-scoped trace summary for one harness execution (one user turn). Pairs with TraceSpan and TraceEvent records.
|
|
3
|
+
*/
|
|
4
|
+
export interface HarnessTrace {
|
|
5
|
+
/**
|
|
6
|
+
* Unique trace identifier (e.g. 'tr_<hex>'). Stable across the lifetime of a single run.
|
|
7
|
+
*/
|
|
8
|
+
traceId: string;
|
|
9
|
+
userId?: string | null;
|
|
10
|
+
chatId?: string | null;
|
|
11
|
+
sessionId?: string | null;
|
|
12
|
+
/**
|
|
13
|
+
* The chat message id this trace was attached to once persisted.
|
|
14
|
+
*/
|
|
15
|
+
assistantMessageId?: string | null;
|
|
16
|
+
status: "running" | "completed" | "error" | "cancelled" | "budget_exhausted";
|
|
17
|
+
durationMs?: number | null;
|
|
18
|
+
hadError: boolean;
|
|
19
|
+
errorMessage?: string | null;
|
|
20
|
+
eventCount: number;
|
|
21
|
+
spanCount: number;
|
|
22
|
+
totalTokens?: number | null;
|
|
23
|
+
/**
|
|
24
|
+
* Primary LLM model identifier used during this trace.
|
|
25
|
+
*/
|
|
26
|
+
modelId?: string | null;
|
|
27
|
+
/**
|
|
28
|
+
* Epoch milliseconds when the run started.
|
|
29
|
+
*/
|
|
30
|
+
startedAtMs?: number | null;
|
|
31
|
+
createdAt: string;
|
|
32
|
+
updatedAt: string;
|
|
33
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface SSEEvent {
|
|
2
|
+
type: "content" | "error" | "agent" | "orchestration" | "loader-hint" | "keepalive" | "done" | "budget_exhausted" | "tool_call" | "tool_result";
|
|
3
|
+
event?: string;
|
|
4
|
+
content?: string;
|
|
5
|
+
hint?: string;
|
|
6
|
+
message?: string;
|
|
7
|
+
code?: string;
|
|
8
|
+
orchestrationGroupId?: string;
|
|
9
|
+
taskId?: string;
|
|
10
|
+
messageId?: string;
|
|
11
|
+
payload?: {
|
|
12
|
+
[k: string]: any;
|
|
13
|
+
};
|
|
14
|
+
[k: string]: any;
|
|
15
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON-RPC 2.0 error object with steerable-specific extensions.
|
|
3
|
+
*/
|
|
4
|
+
export interface SidecarError {
|
|
5
|
+
/**
|
|
6
|
+
* Numeric code. Reuses JSON-RPC reserved codes: -32700 ParseError, -32600 InvalidRequest, -32601 MethodNotFound, -32602 InvalidParams, -32603 InternalError. Steerable extension range -32099..-32000.
|
|
7
|
+
*/
|
|
8
|
+
code: number;
|
|
9
|
+
message: string;
|
|
10
|
+
/**
|
|
11
|
+
* Optional structured details (e.g. budget snapshot, tool stack trace, retry advice).
|
|
12
|
+
*/
|
|
13
|
+
data?: {
|
|
14
|
+
[k: string]: any;
|
|
15
|
+
} | any[] | string | number | boolean | null;
|
|
16
|
+
/**
|
|
17
|
+
* Steerable-specific failure category, parallel to numeric `code`.
|
|
18
|
+
*/
|
|
19
|
+
kind?: "parse" | "invalid_request" | "method_not_found" | "invalid_params" | "internal" | "budget_exhausted" | "policy_denied" | "tool_failed" | "transport_closed" | "timeout" | "cancelled";
|
|
20
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Result payload for the `system.ping` health-check method.
|
|
3
|
+
*/
|
|
4
|
+
export interface SidecarHealth {
|
|
5
|
+
status: "ok" | "degraded" | "starting" | "shutting_down";
|
|
6
|
+
/**
|
|
7
|
+
* Sidecar package version (steerable-agent-runtime).
|
|
8
|
+
*/
|
|
9
|
+
version: string;
|
|
10
|
+
/**
|
|
11
|
+
* Highest spec/sidecar protocol version this sidecar speaks (semver).
|
|
12
|
+
*/
|
|
13
|
+
protocolVersion?: string;
|
|
14
|
+
uptimeMs: number;
|
|
15
|
+
pid?: number;
|
|
16
|
+
pythonVersion?: string;
|
|
17
|
+
/**
|
|
18
|
+
* OS/arch tag (e.g. 'darwin-arm64', 'linux-x64', 'win32-x64').
|
|
19
|
+
*/
|
|
20
|
+
platform?: string;
|
|
21
|
+
/**
|
|
22
|
+
* LLM provider ids currently registered.
|
|
23
|
+
*/
|
|
24
|
+
loadedProviders?: string[];
|
|
25
|
+
loadedTools?: number;
|
|
26
|
+
activeTraces?: number;
|
|
27
|
+
/**
|
|
28
|
+
* Per-subsystem health snapshot.
|
|
29
|
+
*/
|
|
30
|
+
checks?: {
|
|
31
|
+
[k: string]: {
|
|
32
|
+
status: "ok" | "warn" | "error";
|
|
33
|
+
message?: string;
|
|
34
|
+
latencyMs?: number;
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON-RPC 2.0 notification frame (no id, no response). Used by the sidecar to push streaming SSE chunks, lifecycle events, and trace updates back to the host.
|
|
3
|
+
*/
|
|
4
|
+
export interface SidecarNotification {
|
|
5
|
+
jsonrpc: "2.0";
|
|
6
|
+
/**
|
|
7
|
+
* Notification namespace. Reserved: 'stream.chunk', 'stream.done', 'lifecycle.ready', 'lifecycle.shutdown', 'trace.event', 'log.line'.
|
|
8
|
+
*/
|
|
9
|
+
method: string;
|
|
10
|
+
params?: {
|
|
11
|
+
[k: string]: any;
|
|
12
|
+
} | any[] | null;
|
|
13
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON-RPC 2.0 request frame for the steerable-sidecar stdio transport.
|
|
3
|
+
*/
|
|
4
|
+
export interface SidecarRequest {
|
|
5
|
+
jsonrpc: "2.0";
|
|
6
|
+
/**
|
|
7
|
+
* Request id; null is reserved for notifications.
|
|
8
|
+
*/
|
|
9
|
+
id: string | number | null;
|
|
10
|
+
/**
|
|
11
|
+
* Method name. Reserved namespaces: 'system.*' (lifecycle), 'agent.*' (sessions/turns), 'tool.*' (tool router), 'stream.*' (incremental SSE chunks).
|
|
12
|
+
*/
|
|
13
|
+
method: string;
|
|
14
|
+
/**
|
|
15
|
+
* Method-specific arguments. Object form preferred.
|
|
16
|
+
*/
|
|
17
|
+
params?: {
|
|
18
|
+
[k: string]: any;
|
|
19
|
+
} | any[] | null;
|
|
20
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { SidecarError } from "./SidecarError.js";
|
|
2
|
+
/**
|
|
3
|
+
* JSON-RPC 2.0 response frame. Exactly one of `result` or `error` MUST be present.
|
|
4
|
+
*/
|
|
5
|
+
export interface SidecarResponse {
|
|
6
|
+
jsonrpc: "2.0";
|
|
7
|
+
id: string | number | null;
|
|
8
|
+
/**
|
|
9
|
+
* Method-specific success payload.
|
|
10
|
+
*/
|
|
11
|
+
result?: {
|
|
12
|
+
[k: string]: any;
|
|
13
|
+
};
|
|
14
|
+
error?: SidecarError;
|
|
15
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A point-in-time event inside a HarnessTrace. Use this for things that have no measurable duration (notifications, decisions, lifecycle markers).
|
|
3
|
+
*/
|
|
4
|
+
export interface TraceEvent {
|
|
5
|
+
/**
|
|
6
|
+
* Optional storage primary key (cuid).
|
|
7
|
+
*/
|
|
8
|
+
id?: string;
|
|
9
|
+
traceId: string;
|
|
10
|
+
/**
|
|
11
|
+
* Coarse classification used for filtering/UI grouping.
|
|
12
|
+
*/
|
|
13
|
+
kind: "lifecycle" | "policy" | "budget" | "retry" | "tool_call" | "tool_result" | "llm_request" | "llm_response" | "completion" | "error" | "log" | "custom";
|
|
14
|
+
/**
|
|
15
|
+
* Event name (e.g. 'tool.invoked', 'budget.tokens.exhausted').
|
|
16
|
+
*/
|
|
17
|
+
name: string;
|
|
18
|
+
/**
|
|
19
|
+
* Monotonic per-trace ordering value. Stored uniquely with traceId.
|
|
20
|
+
*/
|
|
21
|
+
sequence: number;
|
|
22
|
+
/**
|
|
23
|
+
* Epoch milliseconds when the event was recorded.
|
|
24
|
+
*/
|
|
25
|
+
timestampMs: number;
|
|
26
|
+
/**
|
|
27
|
+
* Optional duration when an event spans a brief work unit.
|
|
28
|
+
*/
|
|
29
|
+
durationMs?: number | null;
|
|
30
|
+
status?: "ok" | "warning" | "error" | null;
|
|
31
|
+
/**
|
|
32
|
+
* JSON-serializable payload, secret-redacted.
|
|
33
|
+
*/
|
|
34
|
+
payload?: {
|
|
35
|
+
[k: string]: any;
|
|
36
|
+
} | null;
|
|
37
|
+
createdAt?: string;
|
|
38
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A timed span within a HarnessTrace. Each span captures a logical step (LLM call, tool call, planning step, etc.).
|
|
3
|
+
*/
|
|
4
|
+
export interface TraceSpan {
|
|
5
|
+
/**
|
|
6
|
+
* Span identifier, unique within its parent trace (e.g. 'step_3').
|
|
7
|
+
*/
|
|
8
|
+
spanId: string;
|
|
9
|
+
/**
|
|
10
|
+
* Parent HarnessTrace id. Optional for in-flight spans before flush.
|
|
11
|
+
*/
|
|
12
|
+
traceId?: string | null;
|
|
13
|
+
/**
|
|
14
|
+
* Optional parent span for nested execution graphs.
|
|
15
|
+
*/
|
|
16
|
+
parentSpanId?: string | null;
|
|
17
|
+
/**
|
|
18
|
+
* Logical operation name (e.g. 'llm.generate', 'tool.shell.exec', 'policy.decide').
|
|
19
|
+
*/
|
|
20
|
+
name: string;
|
|
21
|
+
kind?: "llm" | "tool" | "policy" | "budget" | "retry" | "completion" | "transport" | "storage" | "custom";
|
|
22
|
+
/**
|
|
23
|
+
* Epoch milliseconds when the span opened.
|
|
24
|
+
*/
|
|
25
|
+
startMs: number;
|
|
26
|
+
/**
|
|
27
|
+
* Epoch milliseconds when the span closed. Null while still in flight.
|
|
28
|
+
*/
|
|
29
|
+
endMs?: number | null;
|
|
30
|
+
durationMs?: number | null;
|
|
31
|
+
status: "ok" | "error" | "timeout" | "cancelled" | "running";
|
|
32
|
+
/**
|
|
33
|
+
* Free-form, JSON-serializable, secret-redacted attributes.
|
|
34
|
+
*/
|
|
35
|
+
attrs?: {
|
|
36
|
+
[k: string]: any;
|
|
37
|
+
};
|
|
38
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
package/dist/policy.d.ts
ADDED
package/dist/policy.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export function decideToolMode(toolName) {
|
|
2
|
+
const normalized = toolName.toLowerCase();
|
|
3
|
+
if (normalized.startsWith("get_") || normalized.startsWith("list_") || normalized.startsWith("read_")) {
|
|
4
|
+
return "read";
|
|
5
|
+
}
|
|
6
|
+
if (normalized.startsWith("create_") ||
|
|
7
|
+
normalized.startsWith("update_") ||
|
|
8
|
+
normalized.startsWith("set_") ||
|
|
9
|
+
normalized.startsWith("write_") ||
|
|
10
|
+
normalized.startsWith("apply_")) {
|
|
11
|
+
return "safe_write";
|
|
12
|
+
}
|
|
13
|
+
if (normalized.startsWith("delete_") ||
|
|
14
|
+
normalized.startsWith("drop_") ||
|
|
15
|
+
normalized.startsWith("remove_") ||
|
|
16
|
+
normalized.startsWith("destroy_")) {
|
|
17
|
+
return "destructive";
|
|
18
|
+
}
|
|
19
|
+
return "other";
|
|
20
|
+
}
|
package/dist/retry.d.ts
ADDED
package/dist/retry.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export function nextRetryDelayMs(policy, attempt) {
|
|
2
|
+
const safeAttempt = Math.max(attempt, 1);
|
|
3
|
+
const raw = Math.min(policy.baseDelayMs * 2 ** (safeAttempt - 1), policy.maxDelayMs);
|
|
4
|
+
if (!policy.jitter)
|
|
5
|
+
return raw;
|
|
6
|
+
return Math.max(0, Math.floor(raw * (0.8 + Math.random() * 0.4)));
|
|
7
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export type PatternSeverity = "critical" | "warning";
|
|
2
|
+
export type PatternPlatform = "all" | "unix" | "windows";
|
|
3
|
+
export interface SafetyPatternDef {
|
|
4
|
+
id: string;
|
|
5
|
+
label: string;
|
|
6
|
+
description: string;
|
|
7
|
+
pattern: string;
|
|
8
|
+
category: string;
|
|
9
|
+
severity: PatternSeverity;
|
|
10
|
+
platform: PatternPlatform;
|
|
11
|
+
}
|
|
12
|
+
export declare const BUILTIN_PATTERNS: SafetyPatternDef[];
|
|
13
|
+
export declare function classifyShellCommand(command: string): {
|
|
14
|
+
severity: "safe" | PatternSeverity;
|
|
15
|
+
matchedRules: string[];
|
|
16
|
+
};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
export const BUILTIN_PATTERNS = [
|
|
2
|
+
{
|
|
3
|
+
id: "rm",
|
|
4
|
+
label: "rm 删除",
|
|
5
|
+
description: "匹配 rm 命令",
|
|
6
|
+
pattern: "\\brm\\s",
|
|
7
|
+
category: "file_ops",
|
|
8
|
+
severity: "warning",
|
|
9
|
+
platform: "unix",
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
id: "rm_rf_root",
|
|
13
|
+
label: "rm -rf /",
|
|
14
|
+
description: "递归删除根目录",
|
|
15
|
+
pattern: "rm\\s+-rf\\s+\\/(?:\\s|$)",
|
|
16
|
+
category: "file_ops",
|
|
17
|
+
severity: "critical",
|
|
18
|
+
platform: "unix",
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
id: "sudo",
|
|
22
|
+
label: "sudo 提权",
|
|
23
|
+
description: "以超级用户权限执行",
|
|
24
|
+
pattern: "\\bsudo\\s",
|
|
25
|
+
category: "system",
|
|
26
|
+
severity: "critical",
|
|
27
|
+
platform: "unix",
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
id: "curl_pipe_sh",
|
|
31
|
+
label: "curl | sh",
|
|
32
|
+
description: "从网络下载并直接执行脚本",
|
|
33
|
+
pattern: "\\bcurl\\s.*\\|\\s*(sh|bash|zsh)",
|
|
34
|
+
category: "network",
|
|
35
|
+
severity: "warning",
|
|
36
|
+
platform: "unix",
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
id: "git_push",
|
|
40
|
+
label: "git push / reset --hard",
|
|
41
|
+
description: "Git 远程推送或硬重置",
|
|
42
|
+
pattern: "\\bgit\\s+(push|reset\\s+--hard|clean\\s+-fd)",
|
|
43
|
+
category: "vcs",
|
|
44
|
+
severity: "warning",
|
|
45
|
+
platform: "all",
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
id: "win_del_force",
|
|
49
|
+
label: "del /f /s /q 强制删除",
|
|
50
|
+
description: "强制递归删除整个驱动器",
|
|
51
|
+
pattern: "\\bdel\\s+\\/f\\s+\\/s\\s+\\/q\\s+[a-z]:\\\\",
|
|
52
|
+
category: "windows",
|
|
53
|
+
severity: "critical",
|
|
54
|
+
platform: "windows",
|
|
55
|
+
},
|
|
56
|
+
];
|
|
57
|
+
export function classifyShellCommand(command) {
|
|
58
|
+
const normalized = command.trim();
|
|
59
|
+
if (!normalized)
|
|
60
|
+
return { severity: "safe", matchedRules: [] };
|
|
61
|
+
const matches = BUILTIN_PATTERNS.filter((rule) => {
|
|
62
|
+
const flags = rule.platform === "windows" ? "i" : undefined;
|
|
63
|
+
return new RegExp(rule.pattern, flags).test(normalized);
|
|
64
|
+
});
|
|
65
|
+
if (!matches.length)
|
|
66
|
+
return { severity: "safe", matchedRules: [] };
|
|
67
|
+
return {
|
|
68
|
+
severity: matches.some((m) => m.severity === "critical") ? "critical" : "warning",
|
|
69
|
+
matchedRules: matches.map((m) => m.id),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export interface TraceSpan {
|
|
2
|
+
spanId: string;
|
|
3
|
+
name: string;
|
|
4
|
+
startAt: string;
|
|
5
|
+
endAt?: string;
|
|
6
|
+
attrs?: Record<string, unknown>;
|
|
7
|
+
}
|
|
8
|
+
export declare function createSpan(spanId: string, name: string): TraceSpan;
|
|
9
|
+
export declare function finishSpan(span: TraceSpan): TraceSpan;
|
package/dist/tracing.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@steerable/agent-harness",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Steerable framework Tier 2 — TypeScript facade over the Python harness (policy, budget, retry, completion, tracing) used for cross-language conformance tests. Production code should depend on the Python harness.",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"homepage": "https://pathlyapp.github.io/steerable-framework/",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/pathlyapp/steerable-framework.git",
|
|
10
|
+
"directory": "packages/agent-harness/ts"
|
|
11
|
+
},
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/pathlyapp/steerable-framework/issues"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"steerable",
|
|
17
|
+
"agent",
|
|
18
|
+
"harness",
|
|
19
|
+
"policy",
|
|
20
|
+
"budget",
|
|
21
|
+
"tracing",
|
|
22
|
+
"typescript"
|
|
23
|
+
],
|
|
24
|
+
"type": "module",
|
|
25
|
+
"main": "dist/index.js",
|
|
26
|
+
"types": "dist/index.d.ts",
|
|
27
|
+
"files": [
|
|
28
|
+
"dist",
|
|
29
|
+
"README.md"
|
|
30
|
+
],
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"@steerable/agent-protocol": "0.2.0"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"typescript": "^5.8.3",
|
|
36
|
+
"vitest": "^3.2.4"
|
|
37
|
+
},
|
|
38
|
+
"publishConfig": {
|
|
39
|
+
"access": "public",
|
|
40
|
+
"provenance": true
|
|
41
|
+
},
|
|
42
|
+
"scripts": {
|
|
43
|
+
"gen": "node ../../../scripts/generate_ts.mjs",
|
|
44
|
+
"build": "tsc -p tsconfig.json",
|
|
45
|
+
"test": "vitest run --passWithNoTests",
|
|
46
|
+
"lint": "tsc -p tsconfig.json --noEmit",
|
|
47
|
+
"check:drift": "node ../../../scripts/check_ts_drift.mjs"
|
|
48
|
+
}
|
|
49
|
+
}
|