@smooai/smooth-operator-temporal 1.13.5
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 +21 -0
- package/README.md +43 -0
- package/dist/activities.d.ts +49 -0
- package/dist/activities.d.ts.map +1 -0
- package/dist/activities.js +42 -0
- package/dist/activities.js.map +1 -0
- package/dist/dto.d.ts +117 -0
- package/dist/dto.d.ts.map +1 -0
- package/dist/dto.js +61 -0
- package/dist/dto.js.map +1 -0
- package/dist/executor.d.ts +66 -0
- package/dist/executor.d.ts.map +1 -0
- package/dist/executor.js +89 -0
- package/dist/executor.js.map +1 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -0
- package/dist/signals.d.ts +15 -0
- package/dist/signals.d.ts.map +1 -0
- package/dist/signals.js +16 -0
- package/dist/signals.js.map +1 -0
- package/dist/workflows.d.ts +36 -0
- package/dist/workflows.d.ts.map +1 -0
- package/dist/workflows.js +112 -0
- package/dist/workflows.js.map +1 -0
- package/package.json +50 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Smoo AI, Inc.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# @smooai/smooth-operator-temporal
|
|
2
|
+
|
|
3
|
+
Optional **Temporal-backed durable execution** for the TypeScript
|
|
4
|
+
[`@smooai/smooth-operator-core`](../core) agent engine (ADR-030). The TypeScript
|
|
5
|
+
sibling of the Rust [`smooth-operator-temporal`](../../rust/smooth-operator-temporal)
|
|
6
|
+
crate.
|
|
7
|
+
|
|
8
|
+
An agent turn runs as a Temporal **workflow** whose side-effects — the model call
|
|
9
|
+
and each tool invocation — are Temporal **activities**. The workflow drives the
|
|
10
|
+
engine's deterministic `driveTurn` orchestration **unchanged**, so the durable
|
|
11
|
+
path and the in-process path are the *same loop*. What durability buys: crash-safe
|
|
12
|
+
resume, durable human-in-the-loop via signals, and durable timers (an agent that
|
|
13
|
+
pauses itself for minutes or days and resumes).
|
|
14
|
+
|
|
15
|
+
## Why a separate package
|
|
16
|
+
|
|
17
|
+
Mirrors the Rust crate's off-by-default `temporal` cargo feature: the published
|
|
18
|
+
`@smooai/smooth-operator-core` stays **zero-infra** and never pulls a Temporal SDK
|
|
19
|
+
into a consumer's dependency tree. Only a deployment that wants durable execution
|
|
20
|
+
installs this package. The activity **DTO boundary** (`./dto`) carries no Temporal
|
|
21
|
+
dependency and is always unit-tested.
|
|
22
|
+
|
|
23
|
+
## Shape
|
|
24
|
+
|
|
25
|
+
| Export | Side | Role |
|
|
26
|
+
| ------------------------- | -------- | ---------------------------------------------------------------------- |
|
|
27
|
+
| `TemporalAgentExecutor` | client | The durable `AgentExecutor`; a drop-in for the engine's `InProcessExecutor`. |
|
|
28
|
+
| `createActivities(h)` | worker | Build the worker's activity object from engine handles (model + tools). |
|
|
29
|
+
| `agentTurnWorkflow` | workflow | The turn workflow (registered via the `./workflows` subpath). |
|
|
30
|
+
| `approveToolSignal` / `denyToolSignal` | both | Durable HITL signals. |
|
|
31
|
+
|
|
32
|
+
## Testing
|
|
33
|
+
|
|
34
|
+
```sh
|
|
35
|
+
# Zero-infra DTO boundary unit test (always runs, no Temporal):
|
|
36
|
+
pnpm --filter @smooai/smooth-operator-temporal test
|
|
37
|
+
|
|
38
|
+
# Full e2e against an ephemeral Temporal dev server (health, agent turn,
|
|
39
|
+
# durable timer, HITL) — self-skips offline:
|
|
40
|
+
pnpm --filter @smooai/smooth-operator-core build
|
|
41
|
+
pnpm --filter @smooai/smooth-operator-temporal build
|
|
42
|
+
SMOOTH_TEMPORAL_E2E=1 pnpm --filter @smooai/smooth-operator-temporal test
|
|
43
|
+
```
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Temporal **activities** for the agent-turn workflow: the side-effecting
|
|
3
|
+
* half of a turn (the model call, each tool invocation) plus a liveness probe.
|
|
4
|
+
*
|
|
5
|
+
* The TS sibling of the Rust crate's `AgentTurnActivities`. Where the Rust
|
|
6
|
+
* activities read their engine handles from a process-global installed by
|
|
7
|
+
* `init_engine`, the TypeScript Temporal SDK registers activities as an object
|
|
8
|
+
* passed to `Worker.create({ activities })` — so the handles are simply closed
|
|
9
|
+
* over here via {@link createActivities}, no global needed.
|
|
10
|
+
*
|
|
11
|
+
* Each activity runs in the **normal Node context** (not the deterministic
|
|
12
|
+
* workflow sandbox), so it may import the full engine freely: the model call and
|
|
13
|
+
* tool dispatch are a verbatim reuse of the engine's own
|
|
14
|
+
* {@link InProcessActivities} — the same code the in-process executor runs — with
|
|
15
|
+
* the DTO projection applied on the way out. One implementation, two backends.
|
|
16
|
+
*/
|
|
17
|
+
import type { LlmProvider, Tool, ToolResult } from '@smooai/smooth-operator-core';
|
|
18
|
+
import { type ModelCallInput, type ModelCallOutput, type ToolInvokeInput } from './dto.js';
|
|
19
|
+
/**
|
|
20
|
+
* The engine handles the activities run against — the durable-path analog of the
|
|
21
|
+
* arguments the in-process executor is constructed with.
|
|
22
|
+
*/
|
|
23
|
+
export interface EngineHandles {
|
|
24
|
+
/** The OpenAI-compatible chat client backing the `modelCall` activity. */
|
|
25
|
+
llm: LlmProvider;
|
|
26
|
+
/** The tools dispatchable by the `toolInvoke` activity (default none). */
|
|
27
|
+
tools?: Tool[];
|
|
28
|
+
/** Model id for the request body; defaults to the engine's own default. */
|
|
29
|
+
model?: string;
|
|
30
|
+
}
|
|
31
|
+
/** The activity surface registered with a Temporal worker. */
|
|
32
|
+
export interface AgentTurnActivities {
|
|
33
|
+
/** Liveness probe backing the scaffold health workflow. */
|
|
34
|
+
healthEcho(message: string): Promise<string>;
|
|
35
|
+
/** The model call (`Think`), run as a durable, retried activity. */
|
|
36
|
+
modelCall(input: ModelCallInput): Promise<ModelCallOutput>;
|
|
37
|
+
/** A single tool invocation (`Act`), run as a durable activity. */
|
|
38
|
+
toolInvoke(input: ToolInvokeInput): Promise<ToolResult>;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Build the activity object a Temporal worker registers, bound to `handles`.
|
|
42
|
+
*
|
|
43
|
+
* Tool *business* failures come back inside {@link ToolResult.isError} (not as a
|
|
44
|
+
* thrown activity error), exactly as {@link InProcessActivities.toolInvoke}
|
|
45
|
+
* reports them — matching the engine's own dispatch so the model reacts to a
|
|
46
|
+
* failed tool instead of the turn failing.
|
|
47
|
+
*/
|
|
48
|
+
export declare function createActivities(handles: EngineHandles): AgentTurnActivities;
|
|
49
|
+
//# sourceMappingURL=activities.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"activities.d.ts","sourceRoot":"","sources":["../src/activities.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAElF,OAAO,EAAyB,KAAK,cAAc,EAAE,KAAK,eAAe,EAAE,KAAK,eAAe,EAAE,MAAM,UAAU,CAAC;AAElH;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC1B,0EAA0E;IAC1E,GAAG,EAAE,WAAW,CAAC;IACjB,0EAA0E;IAC1E,KAAK,CAAC,EAAE,IAAI,EAAE,CAAC;IACf,2EAA2E;IAC3E,KAAK,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,8DAA8D;AAC9D,MAAM,WAAW,mBAAmB;IAChC,2DAA2D;IAC3D,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC7C,oEAAoE;IACpE,SAAS,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;IAC3D,mEAAmE;IACnE,UAAU,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;CAC3D;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,aAAa,GAAG,mBAAmB,CAc5E"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Temporal **activities** for the agent-turn workflow: the side-effecting
|
|
3
|
+
* half of a turn (the model call, each tool invocation) plus a liveness probe.
|
|
4
|
+
*
|
|
5
|
+
* The TS sibling of the Rust crate's `AgentTurnActivities`. Where the Rust
|
|
6
|
+
* activities read their engine handles from a process-global installed by
|
|
7
|
+
* `init_engine`, the TypeScript Temporal SDK registers activities as an object
|
|
8
|
+
* passed to `Worker.create({ activities })` — so the handles are simply closed
|
|
9
|
+
* over here via {@link createActivities}, no global needed.
|
|
10
|
+
*
|
|
11
|
+
* Each activity runs in the **normal Node context** (not the deterministic
|
|
12
|
+
* workflow sandbox), so it may import the full engine freely: the model call and
|
|
13
|
+
* tool dispatch are a verbatim reuse of the engine's own
|
|
14
|
+
* {@link InProcessActivities} — the same code the in-process executor runs — with
|
|
15
|
+
* the DTO projection applied on the way out. One implementation, two backends.
|
|
16
|
+
*/
|
|
17
|
+
import { InProcessActivities } from '@smooai/smooth-operator-core/executor';
|
|
18
|
+
import { modelResponseToOutput } from './dto.js';
|
|
19
|
+
/**
|
|
20
|
+
* Build the activity object a Temporal worker registers, bound to `handles`.
|
|
21
|
+
*
|
|
22
|
+
* Tool *business* failures come back inside {@link ToolResult.isError} (not as a
|
|
23
|
+
* thrown activity error), exactly as {@link InProcessActivities.toolInvoke}
|
|
24
|
+
* reports them — matching the engine's own dispatch so the model reacts to a
|
|
25
|
+
* failed tool instead of the turn failing.
|
|
26
|
+
*/
|
|
27
|
+
export function createActivities(handles) {
|
|
28
|
+
const inproc = new InProcessActivities(handles.llm, handles.tools ?? [], handles.model);
|
|
29
|
+
return {
|
|
30
|
+
async healthEcho(message) {
|
|
31
|
+
return `smooth-operator-temporal ok: ${message}`;
|
|
32
|
+
},
|
|
33
|
+
async modelCall(input) {
|
|
34
|
+
const response = await inproc.modelCall(input.messages, input.tools);
|
|
35
|
+
return modelResponseToOutput(response);
|
|
36
|
+
},
|
|
37
|
+
async toolInvoke(input) {
|
|
38
|
+
return inproc.toolInvoke(input.call);
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=activities.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"activities.js","sourceRoot":"","sources":["../src/activities.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,mBAAmB,EAAE,MAAM,uCAAuC,CAAC;AAG5E,OAAO,EAAE,qBAAqB,EAAmE,MAAM,UAAU,CAAC;AAyBlH;;;;;;;GAOG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAAsB;IACnD,MAAM,MAAM,GAAG,IAAI,mBAAmB,CAAC,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,KAAK,IAAI,EAAE,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IACxF,OAAO;QACH,KAAK,CAAC,UAAU,CAAC,OAAe;YAC5B,OAAO,gCAAgC,OAAO,EAAE,CAAC;QACrD,CAAC;QACD,KAAK,CAAC,SAAS,CAAC,KAAqB;YACjC,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;YACrE,OAAO,qBAAqB,CAAC,QAAQ,CAAC,CAAC;QAC3C,CAAC;QACD,KAAK,CAAC,UAAU,CAAC,KAAsB;YACnC,OAAO,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACzC,CAAC;KACJ,CAAC;AACN,CAAC"}
|
package/dist/dto.d.ts
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Data-transfer objects for the Temporal **activity boundary**.
|
|
3
|
+
*
|
|
4
|
+
* The TypeScript port of the Rust crate's `dto.rs`. A Temporal activity
|
|
5
|
+
* serializes its input and output as JSON, so the workflow-side
|
|
6
|
+
* {@link import('@smooai/smooth-operator-core').AgentActivities} surface cannot
|
|
7
|
+
* traffic the raw {@link ModelResponse} (the full OpenAI object) across the
|
|
8
|
+
* boundary directly — it traffics {@link ModelCallOutput}, a projection of the
|
|
9
|
+
* fields the deterministic `driveTurn` orchestration actually reads (`content`,
|
|
10
|
+
* `tool_calls`) plus the accounting fields (`usage`), and the workflow-side
|
|
11
|
+
* adapter reconstructs a minimal {@link ModelResponse} from it via
|
|
12
|
+
* {@link outputToModelResponse}.
|
|
13
|
+
*
|
|
14
|
+
* Everything here is plain data over `@smooai/smooth-operator-core` types and
|
|
15
|
+
* imports **no** `@temporalio/*` package, so it is always built and unit-tested
|
|
16
|
+
* regardless of whether a Temporal runtime is present — exactly like the Rust
|
|
17
|
+
* `dto.rs` compiling without the `temporal` cargo feature.
|
|
18
|
+
*/
|
|
19
|
+
import type { ModelResponse } from '@smooai/smooth-operator-core/executor';
|
|
20
|
+
import type { ToolCall } from '@smooai/smooth-operator-core';
|
|
21
|
+
/** Token usage carried across the activity boundary (OpenAI wire spelling). */
|
|
22
|
+
export interface DtoUsage {
|
|
23
|
+
prompt_tokens: number;
|
|
24
|
+
completion_tokens: number;
|
|
25
|
+
}
|
|
26
|
+
/** Input to the `modelCall` activity: the context window + the tool specs to offer. */
|
|
27
|
+
export interface ModelCallInput {
|
|
28
|
+
/** The conversation context window, as OpenAI-shaped messages. */
|
|
29
|
+
messages: Array<Record<string, unknown>>;
|
|
30
|
+
/** Tool schemas (the OpenAI `tools` array) the model may call; empty means none. */
|
|
31
|
+
tools: Array<Record<string, unknown>>;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Output of the `modelCall` activity: a serde projection of {@link ModelResponse}.
|
|
35
|
+
*
|
|
36
|
+
* Carries the fields the orchestration reads (`content`, `toolCalls`) plus the
|
|
37
|
+
* accounting `usage` so the durable path preserves cost/audit data. Anything the
|
|
38
|
+
* live OpenAI response carries beyond these is transient and dropped — it does
|
|
39
|
+
* not survive (nor need to survive) the activity boundary.
|
|
40
|
+
*/
|
|
41
|
+
export interface ModelCallOutput {
|
|
42
|
+
/** Assistant text content ('' when the model only asked for tools). */
|
|
43
|
+
content: string;
|
|
44
|
+
/** Tool calls the model requested, in OpenAI wire shape. */
|
|
45
|
+
toolCalls: Array<{
|
|
46
|
+
id: string;
|
|
47
|
+
function: {
|
|
48
|
+
name: string;
|
|
49
|
+
arguments: string;
|
|
50
|
+
};
|
|
51
|
+
}>;
|
|
52
|
+
/** Token usage reported by the gateway, if any. */
|
|
53
|
+
usage?: DtoUsage;
|
|
54
|
+
}
|
|
55
|
+
/** Input to the `toolInvoke` activity: the single tool call to execute. */
|
|
56
|
+
export interface ToolInvokeInput {
|
|
57
|
+
/** The tool call (id + name + arguments) to dispatch. */
|
|
58
|
+
call: ToolCall;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Input to the agent-turn workflow — everything needed to seed the conversation
|
|
62
|
+
* and bound the loop. Serializable so it crosses the workflow-start boundary. The
|
|
63
|
+
* TS sibling of Rust's `AgentTurnInput`.
|
|
64
|
+
*/
|
|
65
|
+
export interface AgentTurnInput {
|
|
66
|
+
/** System prompt for the turn. */
|
|
67
|
+
systemPrompt: string;
|
|
68
|
+
/** The user message that opens the turn. */
|
|
69
|
+
userMessage: string;
|
|
70
|
+
/** Prior OpenAI-shaped messages replayed as memory before the user message. */
|
|
71
|
+
history?: Array<Record<string, unknown>>;
|
|
72
|
+
/** Tool schemas (the OpenAI `tools` array) available to the model. */
|
|
73
|
+
tools?: Array<Record<string, unknown>>;
|
|
74
|
+
/** Iteration bound. Omitted / `0` falls back to the loop's default. */
|
|
75
|
+
maxIterations?: number;
|
|
76
|
+
/**
|
|
77
|
+
* Names of tools that require human approval before they run. When the model
|
|
78
|
+
* calls one, the workflow blocks durably until an `approveTool` / `denyTool`
|
|
79
|
+
* signal names that tool call.
|
|
80
|
+
*/
|
|
81
|
+
approvalRequiredTools?: string[];
|
|
82
|
+
/**
|
|
83
|
+
* Name of the built-in **durable wait** tool, if any. A model call to this tool
|
|
84
|
+
* with an integer `seconds` argument sleeps the workflow on a Temporal timer
|
|
85
|
+
* (a durable pause that can span days) instead of dispatching an activity.
|
|
86
|
+
*/
|
|
87
|
+
waitTool?: string;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Result of the agent-turn workflow: the full conversation plus the turn
|
|
91
|
+
* accounting the durable path preserved. Serializable (it is the workflow's
|
|
92
|
+
* return value).
|
|
93
|
+
*/
|
|
94
|
+
export interface AgentTurnResult {
|
|
95
|
+
/** The full conversation (system + user + assistant/tool messages). */
|
|
96
|
+
messages: Array<Record<string, unknown>>;
|
|
97
|
+
/** Number of model-call iterations the loop ran. */
|
|
98
|
+
iterations: number;
|
|
99
|
+
/** Number of tools actually invoked (approval-denied / wait tools excluded). */
|
|
100
|
+
toolCalls: number;
|
|
101
|
+
/** Accumulated token usage across every model call. */
|
|
102
|
+
usage: DtoUsage;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Project a live {@link ModelResponse} down to the serde {@link ModelCallOutput}
|
|
106
|
+
* the activity returns. The TS sibling of Rust's `impl From<&LlmResponse> for
|
|
107
|
+
* ModelCallOutput`.
|
|
108
|
+
*/
|
|
109
|
+
export declare function modelResponseToOutput(response: ModelResponse): ModelCallOutput;
|
|
110
|
+
/**
|
|
111
|
+
* Reconstruct the minimal {@link ModelResponse} the deterministic `driveTurn`
|
|
112
|
+
* loop consumes (`choices[0].message.{content,tool_calls}` + `usage`) from the
|
|
113
|
+
* activity's {@link ModelCallOutput}. The TS sibling of Rust's
|
|
114
|
+
* `ModelCallOutput::into_llm_response`.
|
|
115
|
+
*/
|
|
116
|
+
export declare function outputToModelResponse(output: ModelCallOutput): ModelResponse;
|
|
117
|
+
//# sourceMappingURL=dto.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dto.d.ts","sourceRoot":"","sources":["../src/dto.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uCAAuC,CAAC;AAC3E,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AAE7D,+EAA+E;AAC/E,MAAM,WAAW,QAAQ;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,iBAAiB,EAAE,MAAM,CAAC;CAC7B;AAED,uFAAuF;AACvF,MAAM,WAAW,cAAc;IAC3B,kEAAkE;IAClE,QAAQ,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACzC,oFAAoF;IACpF,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CACzC;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,eAAe;IAC5B,uEAAuE;IACvE,OAAO,EAAE,MAAM,CAAC;IAChB,4DAA4D;IAC5D,SAAS,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,SAAS,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,CAAC,CAAC;IAChF,mDAAmD;IACnD,KAAK,CAAC,EAAE,QAAQ,CAAC;CACpB;AAED,2EAA2E;AAC3E,MAAM,WAAW,eAAe;IAC5B,yDAAyD;IACzD,IAAI,EAAE,QAAQ,CAAC;CAClB;AAED;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC3B,kCAAkC;IAClC,YAAY,EAAE,MAAM,CAAC;IACrB,4CAA4C;IAC5C,WAAW,EAAE,MAAM,CAAC;IACpB,+EAA+E;IAC/E,OAAO,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACzC,sEAAsE;IACtE,KAAK,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACvC,uEAAuE;IACvE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAC;IACjC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC5B,uEAAuE;IACvE,QAAQ,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACzC,oDAAoD;IACpD,UAAU,EAAE,MAAM,CAAC;IACnB,gFAAgF;IAChF,SAAS,EAAE,MAAM,CAAC;IAClB,uDAAuD;IACvD,KAAK,EAAE,QAAQ,CAAC;CACnB;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,aAAa,GAAG,eAAe,CAiB9E;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,eAAe,GAAG,aAAa,CAY5E"}
|
package/dist/dto.js
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Data-transfer objects for the Temporal **activity boundary**.
|
|
3
|
+
*
|
|
4
|
+
* The TypeScript port of the Rust crate's `dto.rs`. A Temporal activity
|
|
5
|
+
* serializes its input and output as JSON, so the workflow-side
|
|
6
|
+
* {@link import('@smooai/smooth-operator-core').AgentActivities} surface cannot
|
|
7
|
+
* traffic the raw {@link ModelResponse} (the full OpenAI object) across the
|
|
8
|
+
* boundary directly — it traffics {@link ModelCallOutput}, a projection of the
|
|
9
|
+
* fields the deterministic `driveTurn` orchestration actually reads (`content`,
|
|
10
|
+
* `tool_calls`) plus the accounting fields (`usage`), and the workflow-side
|
|
11
|
+
* adapter reconstructs a minimal {@link ModelResponse} from it via
|
|
12
|
+
* {@link outputToModelResponse}.
|
|
13
|
+
*
|
|
14
|
+
* Everything here is plain data over `@smooai/smooth-operator-core` types and
|
|
15
|
+
* imports **no** `@temporalio/*` package, so it is always built and unit-tested
|
|
16
|
+
* regardless of whether a Temporal runtime is present — exactly like the Rust
|
|
17
|
+
* `dto.rs` compiling without the `temporal` cargo feature.
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* Project a live {@link ModelResponse} down to the serde {@link ModelCallOutput}
|
|
21
|
+
* the activity returns. The TS sibling of Rust's `impl From<&LlmResponse> for
|
|
22
|
+
* ModelCallOutput`.
|
|
23
|
+
*/
|
|
24
|
+
export function modelResponseToOutput(response) {
|
|
25
|
+
const message = response.choices[0].message;
|
|
26
|
+
const usage = response.usage ?? undefined;
|
|
27
|
+
const out = {
|
|
28
|
+
content: message.content ?? '',
|
|
29
|
+
toolCalls: (message.tool_calls ?? []).map((tc) => ({
|
|
30
|
+
id: tc.id,
|
|
31
|
+
function: { name: tc.function.name, arguments: tc.function.arguments },
|
|
32
|
+
})),
|
|
33
|
+
};
|
|
34
|
+
if (usage) {
|
|
35
|
+
out.usage = {
|
|
36
|
+
prompt_tokens: usage.prompt_tokens ?? 0,
|
|
37
|
+
completion_tokens: usage.completion_tokens ?? 0,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
return out;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Reconstruct the minimal {@link ModelResponse} the deterministic `driveTurn`
|
|
44
|
+
* loop consumes (`choices[0].message.{content,tool_calls}` + `usage`) from the
|
|
45
|
+
* activity's {@link ModelCallOutput}. The TS sibling of Rust's
|
|
46
|
+
* `ModelCallOutput::into_llm_response`.
|
|
47
|
+
*/
|
|
48
|
+
export function outputToModelResponse(output) {
|
|
49
|
+
return {
|
|
50
|
+
choices: [
|
|
51
|
+
{
|
|
52
|
+
message: {
|
|
53
|
+
content: output.content,
|
|
54
|
+
tool_calls: output.toolCalls.length > 0 ? output.toolCalls : null,
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
],
|
|
58
|
+
usage: output.usage ?? null,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=dto.js.map
|
package/dist/dto.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dto.js","sourceRoot":"","sources":["../src/dto.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAwFH;;;;GAIG;AACH,MAAM,UAAU,qBAAqB,CAAC,QAAuB;IACzD,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;IAC5C,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,IAAI,SAAS,CAAC;IAC1C,MAAM,GAAG,GAAoB;QACzB,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,EAAE;QAC9B,SAAS,EAAE,CAAC,OAAO,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;YAC/C,EAAE,EAAE,EAAE,CAAC,EAAE;YACT,QAAQ,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,EAAE,SAAS,EAAE,EAAE,CAAC,QAAQ,CAAC,SAAS,EAAE;SACzE,CAAC,CAAC;KACN,CAAC;IACF,IAAI,KAAK,EAAE,CAAC;QACR,GAAG,CAAC,KAAK,GAAG;YACR,aAAa,EAAE,KAAK,CAAC,aAAa,IAAI,CAAC;YACvC,iBAAiB,EAAE,KAAK,CAAC,iBAAiB,IAAI,CAAC;SAClD,CAAC;IACN,CAAC;IACD,OAAO,GAAG,CAAC;AACf,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CAAC,MAAuB;IACzD,OAAO;QACH,OAAO,EAAE;YACL;gBACI,OAAO,EAAE;oBACL,OAAO,EAAE,MAAM,CAAC,OAAO;oBACvB,UAAU,EAAE,MAAM,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI;iBACpE;aACJ;SACJ;QACD,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,IAAI;KACb,CAAC;AACvB,CAAC"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Temporal-backed {@link AgentExecutor} — the durable sibling of the engine's
|
|
3
|
+
* zero-infra `InProcessExecutor`.
|
|
4
|
+
*
|
|
5
|
+
* It runs a turn by starting the {@link agentTurnWorkflow} on a Temporal cluster
|
|
6
|
+
* and awaiting its result, then shaping the returned conversation into the same
|
|
7
|
+
* {@link AgentRunResponse} `SmoothAgent.run` would produce. A consumer swaps a
|
|
8
|
+
* direct `agent.run(...)` for `executor.execute(agent, ...)` with no other change
|
|
9
|
+
* — the turn now survives a crash, gets durable HITL via signals, and can pause
|
|
10
|
+
* on a durable timer.
|
|
11
|
+
*
|
|
12
|
+
* ## The engine-handle split (mirrors Rust's `init_engine`)
|
|
13
|
+
*
|
|
14
|
+
* A durable turn has two halves in two processes: the **worker** holds the model
|
|
15
|
+
* client + tool *implementations* (via {@link createActivities}); this **executor**
|
|
16
|
+
* (client side) holds the turn *configuration* — system prompt, tool *schemas*,
|
|
17
|
+
* approval/wait policy — supplied at construction. That is why {@link execute}
|
|
18
|
+
* reads its prompt/tools from {@link TemporalAgentExecutorOptions} rather than off
|
|
19
|
+
* the passed `agent` (whose config is private and lives in the worker process).
|
|
20
|
+
* `message` and `history` ARE honored per call.
|
|
21
|
+
*
|
|
22
|
+
* The workflow is started by its **type name** (never by importing the workflow
|
|
23
|
+
* module), so this client-side file pulls in no `@temporalio/workflow` sandbox
|
|
24
|
+
* code — importing that module in a normal Node context throws.
|
|
25
|
+
*/
|
|
26
|
+
import type { Client } from '@temporalio/client';
|
|
27
|
+
import type { AgentExecutor, AgentRunResponse, SmoothAgent, StreamEvent } from '@smooai/smooth-operator-core';
|
|
28
|
+
import type { SmoothAgentThread } from '@smooai/smooth-operator-core';
|
|
29
|
+
/** The Temporal workflow type name the worker registers {@link agentTurnWorkflow} under. */
|
|
30
|
+
export declare const AGENT_TURN_WORKFLOW_TYPE = "agentTurnWorkflow";
|
|
31
|
+
/** Configuration for a {@link TemporalAgentExecutor}. */
|
|
32
|
+
export interface TemporalAgentExecutorOptions {
|
|
33
|
+
/** A connected `@temporalio/client` {@link Client}. */
|
|
34
|
+
client: Client;
|
|
35
|
+
/** The task queue the worker polls (must match the worker's). */
|
|
36
|
+
taskQueue: string;
|
|
37
|
+
/** System prompt for every turn this executor runs. */
|
|
38
|
+
systemPrompt?: string;
|
|
39
|
+
/** OpenAI tool schemas (the `tools` array) offered to the model. */
|
|
40
|
+
tools?: Array<Record<string, unknown>>;
|
|
41
|
+
/** Iteration bound; omitted / `0` uses the engine default. */
|
|
42
|
+
maxIterations?: number;
|
|
43
|
+
/** Tool names gated behind durable human approval (`approveTool` / `denyTool` signals). */
|
|
44
|
+
approvalRequiredTools?: string[];
|
|
45
|
+
/** Name of the durable wait tool, if any. */
|
|
46
|
+
waitTool?: string;
|
|
47
|
+
/** Prefix for generated workflow ids (default `agent-turn`). */
|
|
48
|
+
workflowIdPrefix?: string;
|
|
49
|
+
}
|
|
50
|
+
export declare class TemporalAgentExecutor implements AgentExecutor {
|
|
51
|
+
private readonly options;
|
|
52
|
+
constructor(options: TemporalAgentExecutorOptions);
|
|
53
|
+
execute(_agent: SmoothAgent, message: string, history?: Array<Record<string, unknown>>, _thread?: SmoothAgentThread): Promise<AgentRunResponse>;
|
|
54
|
+
/**
|
|
55
|
+
* A workflow-backed turn has no token-delta stream (its history is the
|
|
56
|
+
* checkpoint, not a live channel), so streaming resolves the durable turn and
|
|
57
|
+
* yields a single terminal `done`.
|
|
58
|
+
*
|
|
59
|
+
* ponytail: no incremental `text` / `tool_call` events on the durable path —
|
|
60
|
+
* a durable turn's progress is observed via workflow history/queries, not a
|
|
61
|
+
* token stream. Upgrade path (per ADR-030's open questions): a workflow-side
|
|
62
|
+
* signal/update channel feeding deltas back to the client.
|
|
63
|
+
*/
|
|
64
|
+
executeStreaming(agent: SmoothAgent, message: string, history?: Array<Record<string, unknown>>, thread?: SmoothAgentThread): AsyncGenerator<StreamEvent>;
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=executor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../src/executor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAIH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAEjD,OAAO,KAAK,EAAE,aAAa,EAAE,gBAAgB,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAC9G,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAItE,4FAA4F;AAC5F,eAAO,MAAM,wBAAwB,sBAAsB,CAAC;AAE5D,yDAAyD;AACzD,MAAM,WAAW,4BAA4B;IACzC,uDAAuD;IACvD,MAAM,EAAE,MAAM,CAAC;IACf,iEAAiE;IACjE,SAAS,EAAE,MAAM,CAAC;IAClB,uDAAuD;IACvD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oEAAoE;IACpE,KAAK,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACvC,8DAA8D;IAC9D,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,2FAA2F;IAC3F,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAC;IACjC,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gEAAgE;IAChE,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,qBAAa,qBAAsB,YAAW,aAAa;IAC3C,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,4BAA4B;IAE5D,OAAO,CACT,MAAM,EAAE,WAAW,EACnB,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACxC,OAAO,CAAC,EAAE,iBAAiB,GAC5B,OAAO,CAAC,gBAAgB,CAAC;IAmB5B;;;;;;;;;OASG;IACI,gBAAgB,CACnB,KAAK,EAAE,WAAW,EAClB,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACxC,MAAM,CAAC,EAAE,iBAAiB,GAC3B,cAAc,CAAC,WAAW,CAAC;CAIjC"}
|
package/dist/executor.js
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Temporal-backed {@link AgentExecutor} — the durable sibling of the engine's
|
|
3
|
+
* zero-infra `InProcessExecutor`.
|
|
4
|
+
*
|
|
5
|
+
* It runs a turn by starting the {@link agentTurnWorkflow} on a Temporal cluster
|
|
6
|
+
* and awaiting its result, then shaping the returned conversation into the same
|
|
7
|
+
* {@link AgentRunResponse} `SmoothAgent.run` would produce. A consumer swaps a
|
|
8
|
+
* direct `agent.run(...)` for `executor.execute(agent, ...)` with no other change
|
|
9
|
+
* — the turn now survives a crash, gets durable HITL via signals, and can pause
|
|
10
|
+
* on a durable timer.
|
|
11
|
+
*
|
|
12
|
+
* ## The engine-handle split (mirrors Rust's `init_engine`)
|
|
13
|
+
*
|
|
14
|
+
* A durable turn has two halves in two processes: the **worker** holds the model
|
|
15
|
+
* client + tool *implementations* (via {@link createActivities}); this **executor**
|
|
16
|
+
* (client side) holds the turn *configuration* — system prompt, tool *schemas*,
|
|
17
|
+
* approval/wait policy — supplied at construction. That is why {@link execute}
|
|
18
|
+
* reads its prompt/tools from {@link TemporalAgentExecutorOptions} rather than off
|
|
19
|
+
* the passed `agent` (whose config is private and lives in the worker process).
|
|
20
|
+
* `message` and `history` ARE honored per call.
|
|
21
|
+
*
|
|
22
|
+
* The workflow is started by its **type name** (never by importing the workflow
|
|
23
|
+
* module), so this client-side file pulls in no `@temporalio/workflow` sandbox
|
|
24
|
+
* code — importing that module in a normal Node context throws.
|
|
25
|
+
*/
|
|
26
|
+
import { randomUUID } from 'node:crypto';
|
|
27
|
+
/** The Temporal workflow type name the worker registers {@link agentTurnWorkflow} under. */
|
|
28
|
+
export const AGENT_TURN_WORKFLOW_TYPE = 'agentTurnWorkflow';
|
|
29
|
+
export class TemporalAgentExecutor {
|
|
30
|
+
options;
|
|
31
|
+
constructor(options) {
|
|
32
|
+
this.options = options;
|
|
33
|
+
}
|
|
34
|
+
async execute(_agent, message, history, _thread) {
|
|
35
|
+
const input = {
|
|
36
|
+
systemPrompt: this.options.systemPrompt ?? '',
|
|
37
|
+
userMessage: message,
|
|
38
|
+
history,
|
|
39
|
+
tools: this.options.tools,
|
|
40
|
+
maxIterations: this.options.maxIterations,
|
|
41
|
+
approvalRequiredTools: this.options.approvalRequiredTools,
|
|
42
|
+
waitTool: this.options.waitTool,
|
|
43
|
+
};
|
|
44
|
+
const workflowId = `${this.options.workflowIdPrefix ?? 'agent-turn'}-${randomUUID()}`;
|
|
45
|
+
const result = await this.options.client.workflow.execute(AGENT_TURN_WORKFLOW_TYPE, {
|
|
46
|
+
taskQueue: this.options.taskQueue,
|
|
47
|
+
workflowId,
|
|
48
|
+
args: [input],
|
|
49
|
+
});
|
|
50
|
+
return toAgentRunResponse(result);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* A workflow-backed turn has no token-delta stream (its history is the
|
|
54
|
+
* checkpoint, not a live channel), so streaming resolves the durable turn and
|
|
55
|
+
* yields a single terminal `done`.
|
|
56
|
+
*
|
|
57
|
+
* ponytail: no incremental `text` / `tool_call` events on the durable path —
|
|
58
|
+
* a durable turn's progress is observed via workflow history/queries, not a
|
|
59
|
+
* token stream. Upgrade path (per ADR-030's open questions): a workflow-side
|
|
60
|
+
* signal/update channel feeding deltas back to the client.
|
|
61
|
+
*/
|
|
62
|
+
async *executeStreaming(agent, message, history, thread) {
|
|
63
|
+
const response = await this.execute(agent, message, history, thread);
|
|
64
|
+
yield { type: 'done', response };
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/** Shape a durable-turn {@link AgentTurnResult} into an engine {@link AgentRunResponse}. */
|
|
68
|
+
function toAgentRunResponse(result) {
|
|
69
|
+
let text = '';
|
|
70
|
+
for (let i = result.messages.length - 1; i >= 0; i--) {
|
|
71
|
+
const msg = result.messages[i];
|
|
72
|
+
if (msg.role === 'assistant' && typeof msg.content === 'string' && msg.content.length > 0) {
|
|
73
|
+
text = msg.content;
|
|
74
|
+
break;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return {
|
|
78
|
+
text,
|
|
79
|
+
iterations: result.iterations,
|
|
80
|
+
toolCalls: result.toolCalls,
|
|
81
|
+
usage: { promptTokens: result.usage.prompt_tokens, completionTokens: result.usage.completion_tokens },
|
|
82
|
+
// ponytail: authoritative per-request cost lives in the gateway's spend
|
|
83
|
+
// logs, not carried back through the workflow boundary. Wire it via the
|
|
84
|
+
// model_call DTO's gateway cost when durable-turn cost attribution lands.
|
|
85
|
+
costUsd: 0,
|
|
86
|
+
budgetExceeded: false,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=executor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executor.js","sourceRoot":"","sources":["../src/executor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AASzC,4FAA4F;AAC5F,MAAM,CAAC,MAAM,wBAAwB,GAAG,mBAAmB,CAAC;AAsB5D,MAAM,OAAO,qBAAqB;IACD;IAA7B,YAA6B,OAAqC;QAArC,YAAO,GAAP,OAAO,CAA8B;IAAG,CAAC;IAEtE,KAAK,CAAC,OAAO,CACT,MAAmB,EACnB,OAAe,EACf,OAAwC,EACxC,OAA2B;QAE3B,MAAM,KAAK,GAAmB;YAC1B,YAAY,EAAE,IAAI,CAAC,OAAO,CAAC,YAAY,IAAI,EAAE;YAC7C,WAAW,EAAE,OAAO;YACpB,OAAO;YACP,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,KAAK;YACzB,aAAa,EAAE,IAAI,CAAC,OAAO,CAAC,aAAa;YACzC,qBAAqB,EAAE,IAAI,CAAC,OAAO,CAAC,qBAAqB;YACzD,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,QAAQ;SAClC,CAAC;QACF,MAAM,UAAU,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,gBAAgB,IAAI,YAAY,IAAI,UAAU,EAAE,EAAE,CAAC;QACtF,MAAM,MAAM,GAAoB,MAAM,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,wBAAwB,EAAE;YACjG,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS;YACjC,UAAU;YACV,IAAI,EAAE,CAAC,KAAK,CAAC;SAChB,CAAC,CAAC;QACH,OAAO,kBAAkB,CAAC,MAAM,CAAC,CAAC;IACtC,CAAC;IAED;;;;;;;;;OASG;IACH,KAAK,CAAC,CAAC,gBAAgB,CACnB,KAAkB,EAClB,OAAe,EACf,OAAwC,EACxC,MAA0B;QAE1B,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;QACrE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;IACrC,CAAC;CACJ;AAED,4FAA4F;AAC5F,SAAS,kBAAkB,CAAC,MAAuB;IAC/C,IAAI,IAAI,GAAG,EAAE,CAAC;IACd,KAAK,IAAI,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QACnD,MAAM,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;QAC/B,IAAI,GAAG,CAAC,IAAI,KAAK,WAAW,IAAI,OAAO,GAAG,CAAC,OAAO,KAAK,QAAQ,IAAI,GAAG,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACxF,IAAI,GAAG,GAAG,CAAC,OAAO,CAAC;YACnB,MAAM;QACV,CAAC;IACL,CAAC;IACD,OAAO;QACH,IAAI;QACJ,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,KAAK,EAAE,EAAE,YAAY,EAAE,MAAM,CAAC,KAAK,CAAC,aAAa,EAAE,gBAAgB,EAAE,MAAM,CAAC,KAAK,CAAC,iBAAiB,EAAE;QACrG,wEAAwE;QACxE,wEAAwE;QACxE,0EAA0E;QAC1E,OAAO,EAAE,CAAC;QACV,cAAc,EAAE,KAAK;KACxB,CAAC;AACN,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @smooai/smooth-operator-temporal — optional Temporal-backed durable execution
|
|
3
|
+
* for the TypeScript smooth-operator engine (ADR-030).
|
|
4
|
+
*
|
|
5
|
+
* The TypeScript sibling of the Rust `smooth-operator-temporal` crate. An agent
|
|
6
|
+
* turn runs as a Temporal workflow ({@link agentTurnWorkflow}) whose model call
|
|
7
|
+
* and tool invocations are activities, driving the engine's deterministic
|
|
8
|
+
* `driveTurn` loop unchanged — the same loop the in-process executor runs.
|
|
9
|
+
*
|
|
10
|
+
* - {@link TemporalAgentExecutor} — the durable {@link AgentExecutor}; a
|
|
11
|
+
* drop-in for the engine's `InProcessExecutor`.
|
|
12
|
+
* - {@link createActivities} — build the worker's activity object from engine
|
|
13
|
+
* handles (model client + tools).
|
|
14
|
+
* - Workflows are also published at the `./workflows` subpath (the path a
|
|
15
|
+
* Temporal worker registers) and activities at `./activities`.
|
|
16
|
+
* - The `./dto` boundary types (re-exported here) carry no Temporal dependency.
|
|
17
|
+
*/
|
|
18
|
+
export type { AgentTurnActivities, EngineHandles } from './activities.js';
|
|
19
|
+
export { createActivities } from './activities.js';
|
|
20
|
+
export type { AgentTurnInput, AgentTurnResult, DtoUsage, ModelCallInput, ModelCallOutput, ToolInvokeInput } from './dto.js';
|
|
21
|
+
export { modelResponseToOutput, outputToModelResponse } from './dto.js';
|
|
22
|
+
export { AGENT_TURN_WORKFLOW_TYPE, TemporalAgentExecutor } from './executor.js';
|
|
23
|
+
export type { TemporalAgentExecutorOptions } from './executor.js';
|
|
24
|
+
export { approveToolSignal, denyToolSignal } from './signals.js';
|
|
25
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,YAAY,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAC1E,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,QAAQ,EAAE,cAAc,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAC5H,OAAO,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AACxE,OAAO,EAAE,wBAAwB,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAChF,YAAY,EAAE,4BAA4B,EAAE,MAAM,eAAe,CAAC;AAKlE,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @smooai/smooth-operator-temporal — optional Temporal-backed durable execution
|
|
3
|
+
* for the TypeScript smooth-operator engine (ADR-030).
|
|
4
|
+
*
|
|
5
|
+
* The TypeScript sibling of the Rust `smooth-operator-temporal` crate. An agent
|
|
6
|
+
* turn runs as a Temporal workflow ({@link agentTurnWorkflow}) whose model call
|
|
7
|
+
* and tool invocations are activities, driving the engine's deterministic
|
|
8
|
+
* `driveTurn` loop unchanged — the same loop the in-process executor runs.
|
|
9
|
+
*
|
|
10
|
+
* - {@link TemporalAgentExecutor} — the durable {@link AgentExecutor}; a
|
|
11
|
+
* drop-in for the engine's `InProcessExecutor`.
|
|
12
|
+
* - {@link createActivities} — build the worker's activity object from engine
|
|
13
|
+
* handles (model client + tools).
|
|
14
|
+
* - Workflows are also published at the `./workflows` subpath (the path a
|
|
15
|
+
* Temporal worker registers) and activities at `./activities`.
|
|
16
|
+
* - The `./dto` boundary types (re-exported here) carry no Temporal dependency.
|
|
17
|
+
*/
|
|
18
|
+
export { createActivities } from './activities.js';
|
|
19
|
+
export { modelResponseToOutput, outputToModelResponse } from './dto.js';
|
|
20
|
+
export { AGENT_TURN_WORKFLOW_TYPE, TemporalAgentExecutor } from './executor.js';
|
|
21
|
+
// Signals are exported from their own context-free module so a client can import
|
|
22
|
+
// them; the workflow functions themselves live at the `./workflows` subpath (the
|
|
23
|
+
// path a Temporal worker registers) and are NOT re-exported here — importing that
|
|
24
|
+
// module in a normal Node process throws (its top-level `proxyActivities`).
|
|
25
|
+
export { approveToolSignal, denyToolSignal } from './signals.js';
|
|
26
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAGH,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAEnD,OAAO,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AACxE,OAAO,EAAE,wBAAwB,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAEhF,iFAAiF;AACjF,iFAAiF;AACjF,kFAAkF;AAClF,4EAA4E;AAC5E,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Signal definitions for the agent-turn workflow, in their own module so they are
|
|
3
|
+
* safe to import from BOTH sides: the workflow (which handles them) and a client
|
|
4
|
+
* (which sends them).
|
|
5
|
+
*
|
|
6
|
+
* {@link defineSignal} only builds a signal descriptor — it needs no workflow
|
|
7
|
+
* context — so importing this file in a normal Node/client process is safe, unlike
|
|
8
|
+
* importing `workflows.ts` (whose top-level `proxyActivities` throws outside a
|
|
9
|
+
* workflow).
|
|
10
|
+
*/
|
|
11
|
+
/** A human approves the tool call with this id, unblocking the durable HITL gate. */
|
|
12
|
+
export declare const approveToolSignal: import("@temporalio/workflow").SignalDefinition<[string], string>;
|
|
13
|
+
/** A human denies the tool call with this id; the gate skips it with an error result. */
|
|
14
|
+
export declare const denyToolSignal: import("@temporalio/workflow").SignalDefinition<[string], string>;
|
|
15
|
+
//# sourceMappingURL=signals.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signals.d.ts","sourceRoot":"","sources":["../src/signals.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,qFAAqF;AACrF,eAAO,MAAM,iBAAiB,mEAAwC,CAAC;AACvE,yFAAyF;AACzF,eAAO,MAAM,cAAc,mEAAqC,CAAC"}
|
package/dist/signals.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Signal definitions for the agent-turn workflow, in their own module so they are
|
|
3
|
+
* safe to import from BOTH sides: the workflow (which handles them) and a client
|
|
4
|
+
* (which sends them).
|
|
5
|
+
*
|
|
6
|
+
* {@link defineSignal} only builds a signal descriptor — it needs no workflow
|
|
7
|
+
* context — so importing this file in a normal Node/client process is safe, unlike
|
|
8
|
+
* importing `workflows.ts` (whose top-level `proxyActivities` throws outside a
|
|
9
|
+
* workflow).
|
|
10
|
+
*/
|
|
11
|
+
import { defineSignal } from '@temporalio/workflow';
|
|
12
|
+
/** A human approves the tool call with this id, unblocking the durable HITL gate. */
|
|
13
|
+
export const approveToolSignal = defineSignal('approveTool');
|
|
14
|
+
/** A human denies the tool call with this id; the gate skips it with an error result. */
|
|
15
|
+
export const denyToolSignal = defineSignal('denyTool');
|
|
16
|
+
//# sourceMappingURL=signals.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signals.js","sourceRoot":"","sources":["../src/signals.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEpD,qFAAqF;AACrF,MAAM,CAAC,MAAM,iBAAiB,GAAG,YAAY,CAAW,aAAa,CAAC,CAAC;AACvE,yFAAyF;AACzF,MAAM,CAAC,MAAM,cAAc,GAAG,YAAY,CAAW,UAAU,CAAC,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Temporal **workflows** (the deterministic half of durable execution).
|
|
3
|
+
*
|
|
4
|
+
* The TS sibling of the Rust crate's `AgentTurnWorkflow` + `HealthWorkflow`. An
|
|
5
|
+
* agent turn runs as {@link agentTurnWorkflow}, which drives the engine's
|
|
6
|
+
* deterministic {@link driveTurn} orchestration **unchanged** over an adapter
|
|
7
|
+
* that schedules the model call and each tool invocation as Temporal activities.
|
|
8
|
+
* The in-process executor runs the same `driveTurn` inline — one loop, two
|
|
9
|
+
* backends.
|
|
10
|
+
*
|
|
11
|
+
* This module runs in Temporal's **deterministic workflow sandbox**, so it may
|
|
12
|
+
* import only replay-safe code: `@temporalio/workflow` primitives, the pure
|
|
13
|
+
* `driveTurn` + its types from `@smooai/smooth-operator-core/executor` (that
|
|
14
|
+
* entry point has zero runtime imports — it is type-only), and the plain DTO
|
|
15
|
+
* helpers. It performs no I/O, clock reads, or RNG of its own — every
|
|
16
|
+
* side-effect is a scheduled activity, every wait a durable `sleep`/`condition`.
|
|
17
|
+
*/
|
|
18
|
+
import { type AgentTurnInput, type AgentTurnResult } from './dto.js';
|
|
19
|
+
/**
|
|
20
|
+
* Run one agent turn as a durable workflow. Seeds the conversation (system +
|
|
21
|
+
* history + user), then drives {@link driveTurn} over an activity-scheduling
|
|
22
|
+
* adapter, and returns the full conversation plus turn accounting.
|
|
23
|
+
*
|
|
24
|
+
* Durable human-in-the-loop and durable timers live in the adapter, not in
|
|
25
|
+
* `driveTurn`: an approval-gated tool blocks on {@link condition} until an
|
|
26
|
+
* `approveTool` / `denyTool` signal names its call id, and the configured wait
|
|
27
|
+
* tool sleeps on a durable {@link sleep} timer — both recorded in workflow
|
|
28
|
+
* history, so they survive worker restarts and can resolve arbitrarily later.
|
|
29
|
+
*/
|
|
30
|
+
export declare function agentTurnWorkflow(input: AgentTurnInput): Promise<AgentTurnResult>;
|
|
31
|
+
/**
|
|
32
|
+
* Scaffold liveness workflow — proves the SDK integrates end to end and backs the
|
|
33
|
+
* health e2e. The TS sibling of the Rust crate's `HealthWorkflow`.
|
|
34
|
+
*/
|
|
35
|
+
export declare function healthWorkflow(message: string): Promise<string>;
|
|
36
|
+
//# sourceMappingURL=workflows.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workflows.d.ts","sourceRoot":"","sources":["../src/workflows.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAUH,OAAO,EAAyB,KAAK,cAAc,EAAE,KAAK,eAAe,EAAE,MAAM,UAAU,CAAC;AAY5F;;;;;;;;;;GAUG;AACH,wBAAsB,iBAAiB,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC,CAmEvF;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAErE"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Temporal **workflows** (the deterministic half of durable execution).
|
|
3
|
+
*
|
|
4
|
+
* The TS sibling of the Rust crate's `AgentTurnWorkflow` + `HealthWorkflow`. An
|
|
5
|
+
* agent turn runs as {@link agentTurnWorkflow}, which drives the engine's
|
|
6
|
+
* deterministic {@link driveTurn} orchestration **unchanged** over an adapter
|
|
7
|
+
* that schedules the model call and each tool invocation as Temporal activities.
|
|
8
|
+
* The in-process executor runs the same `driveTurn` inline — one loop, two
|
|
9
|
+
* backends.
|
|
10
|
+
*
|
|
11
|
+
* This module runs in Temporal's **deterministic workflow sandbox**, so it may
|
|
12
|
+
* import only replay-safe code: `@temporalio/workflow` primitives, the pure
|
|
13
|
+
* `driveTurn` + its types from `@smooai/smooth-operator-core/executor` (that
|
|
14
|
+
* entry point has zero runtime imports — it is type-only), and the plain DTO
|
|
15
|
+
* helpers. It performs no I/O, clock reads, or RNG of its own — every
|
|
16
|
+
* side-effect is a scheduled activity, every wait a durable `sleep`/`condition`.
|
|
17
|
+
*/
|
|
18
|
+
import { condition, proxyActivities, setHandler, sleep } from '@temporalio/workflow';
|
|
19
|
+
import { driveTurn } from '@smooai/smooth-operator-core/executor';
|
|
20
|
+
import { outputToModelResponse } from './dto.js';
|
|
21
|
+
import { approveToolSignal, denyToolSignal } from './signals.js';
|
|
22
|
+
/**
|
|
23
|
+
* Activity stubs. 60s start-to-close mirrors the Rust crate's
|
|
24
|
+
* `agent_activity_opts`; the SDK's default retry policy makes transient model /
|
|
25
|
+
* tool failures durable retries rather than turn failures.
|
|
26
|
+
*/
|
|
27
|
+
const { modelCall, toolInvoke, healthEcho } = proxyActivities({
|
|
28
|
+
startToCloseTimeout: '60s',
|
|
29
|
+
});
|
|
30
|
+
/**
|
|
31
|
+
* Run one agent turn as a durable workflow. Seeds the conversation (system +
|
|
32
|
+
* history + user), then drives {@link driveTurn} over an activity-scheduling
|
|
33
|
+
* adapter, and returns the full conversation plus turn accounting.
|
|
34
|
+
*
|
|
35
|
+
* Durable human-in-the-loop and durable timers live in the adapter, not in
|
|
36
|
+
* `driveTurn`: an approval-gated tool blocks on {@link condition} until an
|
|
37
|
+
* `approveTool` / `denyTool` signal names its call id, and the configured wait
|
|
38
|
+
* tool sleeps on a durable {@link sleep} timer — both recorded in workflow
|
|
39
|
+
* history, so they survive worker restarts and can resolve arbitrarily later.
|
|
40
|
+
*/
|
|
41
|
+
export async function agentTurnWorkflow(input) {
|
|
42
|
+
const approved = new Set();
|
|
43
|
+
const denied = new Set();
|
|
44
|
+
setHandler(approveToolSignal, (callId) => {
|
|
45
|
+
approved.add(callId);
|
|
46
|
+
});
|
|
47
|
+
setHandler(denyToolSignal, (callId) => {
|
|
48
|
+
denied.add(callId);
|
|
49
|
+
});
|
|
50
|
+
const messages = [];
|
|
51
|
+
if (input.systemPrompt)
|
|
52
|
+
messages.push({ role: 'system', content: input.systemPrompt });
|
|
53
|
+
if (input.history)
|
|
54
|
+
messages.push(...input.history);
|
|
55
|
+
messages.push({ role: 'user', content: input.userMessage });
|
|
56
|
+
let iterations = 0;
|
|
57
|
+
let toolCalls = 0;
|
|
58
|
+
const usage = { prompt_tokens: 0, completion_tokens: 0 };
|
|
59
|
+
const approvalRequired = input.approvalRequiredTools ?? [];
|
|
60
|
+
const activities = {
|
|
61
|
+
async modelCall(msgs, tools) {
|
|
62
|
+
iterations += 1;
|
|
63
|
+
const output = await modelCall({ messages: msgs, tools });
|
|
64
|
+
if (output.usage) {
|
|
65
|
+
usage.prompt_tokens += output.usage.prompt_tokens;
|
|
66
|
+
usage.completion_tokens += output.usage.completion_tokens;
|
|
67
|
+
}
|
|
68
|
+
return outputToModelResponse(output);
|
|
69
|
+
},
|
|
70
|
+
async toolInvoke(call) {
|
|
71
|
+
// Durable wait: the configured wait tool sleeps on a Temporal timer
|
|
72
|
+
// instead of dispatching an activity. Recorded in history, so the
|
|
73
|
+
// pause survives restarts and can span days.
|
|
74
|
+
if (input.waitTool !== undefined && call.name === input.waitTool) {
|
|
75
|
+
const raw = call.arguments.seconds;
|
|
76
|
+
const seconds = typeof raw === 'number' ? raw : Number(raw);
|
|
77
|
+
if (!Number.isInteger(seconds) || seconds < 0) {
|
|
78
|
+
return { toolCallId: call.id, content: `wait tool '${call.name}' requires an integer 'seconds' argument`, isError: true };
|
|
79
|
+
}
|
|
80
|
+
await sleep(seconds * 1000);
|
|
81
|
+
return { toolCallId: call.id, content: `Waited ${seconds}s (durable timer).`, isError: false };
|
|
82
|
+
}
|
|
83
|
+
// Durable human-in-the-loop gate: block until a signal names this call
|
|
84
|
+
// id. `driveTurn` is unchanged — the gate lives here.
|
|
85
|
+
if (approvalRequired.includes(call.name)) {
|
|
86
|
+
await condition(() => approved.has(call.id) || denied.has(call.id));
|
|
87
|
+
if (denied.has(call.id)) {
|
|
88
|
+
return { toolCallId: call.id, content: `Tool call '${call.name}' was denied by human approval.`, isError: true };
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
toolCalls += 1;
|
|
92
|
+
return toolInvoke({ call });
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
if (input.maxIterations !== undefined && input.maxIterations > 0) {
|
|
96
|
+
await driveTurn(activities, messages, input.tools ?? [], { maxIterations: input.maxIterations });
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
// Omit the policy so the engine's own default iteration bound applies —
|
|
100
|
+
// never a magic number duplicated here.
|
|
101
|
+
await driveTurn(activities, messages, input.tools ?? []);
|
|
102
|
+
}
|
|
103
|
+
return { messages, iterations, toolCalls, usage };
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Scaffold liveness workflow — proves the SDK integrates end to end and backs the
|
|
107
|
+
* health e2e. The TS sibling of the Rust crate's `HealthWorkflow`.
|
|
108
|
+
*/
|
|
109
|
+
export async function healthWorkflow(message) {
|
|
110
|
+
return healthEcho(message);
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=workflows.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workflows.js","sourceRoot":"","sources":["../src/workflows.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@smooai/smooth-operator-temporal",
|
|
3
|
+
"version": "1.13.5",
|
|
4
|
+
"description": "Optional Temporal-backed durable execution backend for the smooth-operator agent engine (ADR-030). The TypeScript sibling of the Rust `smooth-operator-temporal` crate — an agent turn runs as a Temporal workflow whose model call and tool invocations are activities, driving the same `driveTurn` loop as the in-process executor.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/SmooAI/smooth-operator-core.git",
|
|
10
|
+
"directory": "typescript/temporal"
|
|
11
|
+
},
|
|
12
|
+
"homepage": "https://github.com/SmooAI/smooth-operator-core/tree/main/typescript/temporal",
|
|
13
|
+
"main": "./dist/index.js",
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"exports": {
|
|
16
|
+
".": {
|
|
17
|
+
"types": "./dist/index.d.ts",
|
|
18
|
+
"import": "./dist/index.js"
|
|
19
|
+
},
|
|
20
|
+
"./workflows": {
|
|
21
|
+
"types": "./dist/workflows.d.ts",
|
|
22
|
+
"import": "./dist/workflows.js"
|
|
23
|
+
},
|
|
24
|
+
"./activities": {
|
|
25
|
+
"types": "./dist/activities.d.ts",
|
|
26
|
+
"import": "./dist/activities.js"
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"files": [
|
|
30
|
+
"dist"
|
|
31
|
+
],
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"@temporalio/activity": "^1.11.0",
|
|
34
|
+
"@temporalio/client": "^1.11.0",
|
|
35
|
+
"@temporalio/worker": "^1.11.0",
|
|
36
|
+
"@temporalio/workflow": "^1.11.0",
|
|
37
|
+
"@smooai/smooth-operator-core": "1.13.5"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@temporalio/testing": "^1.11.0",
|
|
41
|
+
"@types/node": "^25.9.2",
|
|
42
|
+
"typescript": "^5.7.3",
|
|
43
|
+
"vitest": "^2.1.8"
|
|
44
|
+
},
|
|
45
|
+
"scripts": {
|
|
46
|
+
"build": "tsc -p tsconfig.build.json",
|
|
47
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
48
|
+
"test": "vitest run"
|
|
49
|
+
}
|
|
50
|
+
}
|