@agentick/core 0.2.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +222 -23
- package/dist/.tsbuildinfo.build +1 -1
- package/dist/agentick-instance.d.ts.map +1 -1
- package/dist/agentick-instance.js +125 -119
- package/dist/agentick-instance.js.map +1 -1
- package/dist/app/session-store.d.ts +1 -1
- package/dist/app/session-store.js +1 -1
- package/dist/app/session.d.ts +26 -17
- package/dist/app/session.d.ts.map +1 -1
- package/dist/app/session.js +220 -202
- package/dist/app/session.js.map +1 -1
- package/dist/app/types.d.ts +230 -149
- package/dist/app/types.d.ts.map +1 -1
- package/dist/com/object-model.d.ts +7 -4
- package/dist/com/object-model.d.ts.map +1 -1
- package/dist/com/object-model.js +13 -4
- package/dist/com/object-model.js.map +1 -1
- package/dist/compiler/fiber-compiler.d.ts +8 -16
- package/dist/compiler/fiber-compiler.d.ts.map +1 -1
- package/dist/compiler/fiber-compiler.js +10 -31
- package/dist/compiler/fiber-compiler.js.map +1 -1
- package/dist/component/component.d.ts +6 -6
- package/dist/component/component.d.ts.map +1 -1
- package/dist/engine/tool-executor.js +3 -3
- package/dist/engine/tool-executor.js.map +1 -1
- package/dist/hooks/com-state.d.ts +14 -1
- package/dist/hooks/com-state.d.ts.map +1 -1
- package/dist/hooks/com-state.js +28 -2
- package/dist/hooks/com-state.js.map +1 -1
- package/dist/hooks/context-info.d.ts +2 -35
- package/dist/hooks/context-info.d.ts.map +1 -1
- package/dist/hooks/context-info.js +8 -0
- package/dist/hooks/context-info.js.map +1 -1
- package/dist/hooks/context.d.ts +1 -2
- package/dist/hooks/context.d.ts.map +1 -1
- package/dist/hooks/context.js +1 -2
- package/dist/hooks/context.js.map +1 -1
- package/dist/hooks/data.d.ts +18 -1
- package/dist/hooks/data.d.ts.map +1 -1
- package/dist/hooks/data.js +13 -2
- package/dist/hooks/data.js.map +1 -1
- package/dist/hooks/index.d.ts +5 -3
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +5 -1
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/resolved.d.ts +2 -0
- package/dist/hooks/resolved.d.ts.map +1 -0
- package/dist/hooks/resolved.js +6 -0
- package/dist/hooks/resolved.js.map +1 -0
- package/dist/hooks/runtime-context.d.ts +45 -0
- package/dist/hooks/runtime-context.d.ts.map +1 -1
- package/dist/hooks/runtime-context.js +35 -0
- package/dist/hooks/runtime-context.js.map +1 -1
- package/dist/hooks/timeline.d.ts +10 -0
- package/dist/hooks/timeline.d.ts.map +1 -0
- package/dist/hooks/timeline.js +13 -0
- package/dist/hooks/timeline.js.map +1 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -1
- package/dist/jsx/components/timeline.d.ts.map +1 -1
- package/dist/jsx/components/timeline.js +11 -11
- package/dist/jsx/components/timeline.js.map +1 -1
- package/dist/local-transport.d.ts +31 -0
- package/dist/local-transport.d.ts.map +1 -0
- package/dist/local-transport.js +119 -0
- package/dist/local-transport.js.map +1 -0
- package/dist/model/model.d.ts +0 -2
- package/dist/model/model.d.ts.map +1 -1
- package/dist/model/model.js.map +1 -1
- package/dist/procedure/index.d.ts.map +1 -1
- package/dist/testing/index.d.ts +2 -0
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +2 -0
- package/dist/testing/index.js.map +1 -1
- package/dist/testing/mock-app.d.ts.map +1 -1
- package/dist/testing/mock-app.js +5 -15
- package/dist/testing/mock-app.js.map +1 -1
- package/dist/testing/mocks.d.ts +2 -3
- package/dist/testing/mocks.d.ts.map +1 -1
- package/dist/testing/mocks.js +2 -3
- package/dist/testing/mocks.js.map +1 -1
- package/dist/testing/render-agent.d.ts +1 -1
- package/dist/testing/render-agent.d.ts.map +1 -1
- package/dist/testing/render-agent.js +5 -5
- package/dist/testing/render-agent.js.map +1 -1
- package/dist/testing/test-runner.d.ts +122 -0
- package/dist/testing/test-runner.d.ts.map +1 -0
- package/dist/testing/test-runner.js +126 -0
- package/dist/testing/test-runner.js.map +1 -0
- package/dist/tool/tool.d.ts +47 -1
- package/dist/tool/tool.d.ts.map +1 -1
- package/dist/tool/tool.js +51 -14
- package/dist/tool/tool.js.map +1 -1
- package/package.json +4 -4
- package/dist/hibernation/index.d.ts +0 -126
- package/dist/hibernation/index.d.ts.map +0 -1
- package/dist/hibernation/index.js +0 -127
- package/dist/hibernation/index.js.map +0 -1
package/README.md
CHANGED
|
@@ -592,6 +592,18 @@ const WeatherTool = createTool({
|
|
|
592
592
|
render: (tickState, ctx) => <Section id="weather-info">Last checked: {lastChecked}</Section>,
|
|
593
593
|
});
|
|
594
594
|
|
|
595
|
+
// Tools can capture tree-scoped context via use():
|
|
596
|
+
const ShellTool = createTool({
|
|
597
|
+
name: "shell",
|
|
598
|
+
description: "Execute a command in the sandbox",
|
|
599
|
+
input: z.object({ command: z.string() }),
|
|
600
|
+
use: () => ({ sandbox: useSandbox() }), // runs at render time
|
|
601
|
+
handler: async ({ command }, deps) => {
|
|
602
|
+
const result = await deps!.sandbox.exec(command);
|
|
603
|
+
return [{ type: "text", text: result.stdout }];
|
|
604
|
+
},
|
|
605
|
+
});
|
|
606
|
+
|
|
595
607
|
// Use in your app
|
|
596
608
|
function App() {
|
|
597
609
|
return (
|
|
@@ -626,6 +638,7 @@ const app = createApp(MyApp, {
|
|
|
626
638
|
devTools: true, // Enable DevTools emission
|
|
627
639
|
tools: [ExternalTool], // Additional tools (merged with JSX <Tool>s)
|
|
628
640
|
mcpServers: { ... }, // MCP server configs
|
|
641
|
+
runner: myRunner, // Execution runner (see below)
|
|
629
642
|
});
|
|
630
643
|
```
|
|
631
644
|
|
|
@@ -741,43 +754,139 @@ const DelegateTool = createTool({
|
|
|
741
754
|
- **Depth limit**: Maximum 10 levels of nesting (throws if exceeded).
|
|
742
755
|
- **Cleanup**: Children are removed from `session.children` when they complete.
|
|
743
756
|
|
|
744
|
-
### Session Persistence
|
|
757
|
+
### Session Persistence
|
|
745
758
|
|
|
746
|
-
|
|
759
|
+
Sessions auto-persist after each execution and auto-restore when accessed via `app.session(id)`.
|
|
747
760
|
|
|
748
761
|
```typescript
|
|
749
762
|
const app = createApp(MyApp, {
|
|
750
763
|
model,
|
|
751
764
|
sessions: {
|
|
752
|
-
store:
|
|
753
|
-
maxActive: 100, // Max concurrent sessions
|
|
754
|
-
idleTimeout: 5 * 60 * 1000, //
|
|
755
|
-
autoHibernate: true, // Auto-hibernate on idle
|
|
765
|
+
store: "./data/sessions.db", // SQLite file (or ':memory:', or custom SessionStore)
|
|
766
|
+
maxActive: 100, // Max concurrent in-memory sessions
|
|
767
|
+
idleTimeout: 5 * 60 * 1000, // Evict from memory after 5 min idle
|
|
756
768
|
},
|
|
769
|
+
});
|
|
770
|
+
```
|
|
757
771
|
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
772
|
+
**How it works:**
|
|
773
|
+
|
|
774
|
+
1. After each execution, session state is auto-saved to the store (fire-and-forget — persist failures don't block execution)
|
|
775
|
+
2. When `app.session("user-123")` is called and the session isn't in memory, it's auto-restored from the store
|
|
776
|
+
3. `useComState` and `useData` values are included in snapshots by default (set `{ persist: false }` to exclude)
|
|
777
|
+
4. `maxActive` and `idleTimeout` control memory — evicted sessions can be restored from store
|
|
778
|
+
|
|
779
|
+
#### Snapshot Contents
|
|
780
|
+
|
|
781
|
+
A `SessionSnapshot` captures:
|
|
782
|
+
|
|
783
|
+
| Field | Type | Description |
|
|
784
|
+
| ----------- | --------------------------- | ------------------------------------------------------ |
|
|
785
|
+
| `timeline` | `COMTimelineEntry[] ∣ null` | Full conversation history |
|
|
786
|
+
| `comState` | `Record<string, unknown>` | All `useComState` values (with `persist !== false`) |
|
|
787
|
+
| `dataCache` | `Record<string, ...>` | All `useData` cached values (with `persist !== false`) |
|
|
788
|
+
| `tick` | `number` | Tick count at snapshot time |
|
|
789
|
+
| `usage` | `UsageStats` | Accumulated token usage |
|
|
790
|
+
|
|
791
|
+
#### Lifecycle Hooks
|
|
792
|
+
|
|
793
|
+
```typescript
|
|
794
|
+
const app = createApp(MyApp, {
|
|
795
|
+
model,
|
|
796
|
+
sessions: { store: "./sessions.db" },
|
|
797
|
+
|
|
798
|
+
// Before save — cancel or modify snapshot
|
|
799
|
+
onBeforePersist: (session, snapshot) => {
|
|
800
|
+
if (snapshot.tick < 2) return false; // Don't persist short sessions
|
|
764
801
|
},
|
|
765
802
|
|
|
766
|
-
//
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
if (session.inspect().lastToolCalls.length > 0) return false;
|
|
803
|
+
// After save
|
|
804
|
+
onAfterPersist: (sessionId, snapshot) => {
|
|
805
|
+
console.log(`Saved session ${sessionId}`);
|
|
770
806
|
},
|
|
771
|
-
|
|
772
|
-
|
|
807
|
+
|
|
808
|
+
// Before restore — migrate old formats
|
|
809
|
+
onBeforeRestore: (sessionId, snapshot) => {
|
|
810
|
+
if (snapshot.version !== "1.0") return migrateSnapshot(snapshot);
|
|
773
811
|
},
|
|
774
|
-
|
|
775
|
-
|
|
812
|
+
|
|
813
|
+
// After restore
|
|
814
|
+
onAfterRestore: (session, snapshot) => {
|
|
815
|
+
console.log(`Restored session ${session.id} at tick ${snapshot.tick}`);
|
|
776
816
|
},
|
|
777
|
-
|
|
778
|
-
|
|
817
|
+
});
|
|
818
|
+
```
|
|
819
|
+
|
|
820
|
+
#### Restore Layers
|
|
821
|
+
|
|
822
|
+
**Layer 1 (default):** Snapshot data is auto-applied. Timeline, comState, and dataCache are restored directly. Components see their previous state via `useComState` and `useData`.
|
|
823
|
+
|
|
824
|
+
**Layer 2 (resolve):** When `resolve` is configured, auto-apply is disabled. Resolve functions control reconstruction and receive the snapshot as context. Results are available via `useResolved(key)`.
|
|
825
|
+
|
|
826
|
+
```typescript
|
|
827
|
+
const app = createApp(MyApp, {
|
|
828
|
+
model,
|
|
829
|
+
sessions: { store: "./sessions.db" },
|
|
830
|
+
|
|
831
|
+
// Layer 2: resolve controls reconstruction
|
|
832
|
+
resolve: {
|
|
833
|
+
greeting: (ctx) => `Welcome back! You were on tick ${ctx.snapshot?.tick}`,
|
|
834
|
+
userData: async (ctx) => fetchUser(ctx.sessionId),
|
|
779
835
|
},
|
|
780
836
|
});
|
|
837
|
+
|
|
838
|
+
// In components:
|
|
839
|
+
function MyAgent() {
|
|
840
|
+
const greeting = useResolved<string>("greeting");
|
|
841
|
+
const userData = useResolved<User>("userData");
|
|
842
|
+
// ...
|
|
843
|
+
}
|
|
844
|
+
```
|
|
845
|
+
|
|
846
|
+
#### Context Management vs History
|
|
847
|
+
|
|
848
|
+
The session's `_timeline` is the append-only historical log — it grows with every message. The `<Timeline>` component controls what the model _sees_ (context) via its props:
|
|
849
|
+
|
|
850
|
+
```tsx
|
|
851
|
+
// Full history → model context (default)
|
|
852
|
+
<Timeline />
|
|
853
|
+
|
|
854
|
+
// Only recent messages in context
|
|
855
|
+
<Timeline limit={20} />
|
|
856
|
+
|
|
857
|
+
// Token-budgeted context
|
|
858
|
+
<Timeline maxTokens={8000} strategy="sliding-window" headroom={500} />
|
|
859
|
+
|
|
860
|
+
// Role filtering
|
|
861
|
+
<Timeline roles={['user', 'assistant']} />
|
|
862
|
+
```
|
|
863
|
+
|
|
864
|
+
The `useTimeline()` hook provides direct access for advanced patterns:
|
|
865
|
+
|
|
866
|
+
```tsx
|
|
867
|
+
function MyAgent() {
|
|
868
|
+
const timeline = useTimeline();
|
|
869
|
+
|
|
870
|
+
// Read current entries
|
|
871
|
+
console.log(timeline.entries.length);
|
|
872
|
+
|
|
873
|
+
// Replace timeline (e.g., after summarization)
|
|
874
|
+
timeline.set([summaryEntry, ...recentEntries]);
|
|
875
|
+
|
|
876
|
+
// Transform timeline
|
|
877
|
+
timeline.update((entries) => entries.filter((e) => e.message.role !== "system"));
|
|
878
|
+
}
|
|
879
|
+
```
|
|
880
|
+
|
|
881
|
+
#### `maxTimelineEntries` — OOM Safety Net
|
|
882
|
+
|
|
883
|
+
For long-running sessions, `maxTimelineEntries` prevents unbounded memory growth by trimming the oldest entries after each tick. This is a safety net, not a context management strategy — use `<Timeline>` props for context control.
|
|
884
|
+
|
|
885
|
+
```typescript
|
|
886
|
+
const app = createApp(MyApp, {
|
|
887
|
+
model,
|
|
888
|
+
maxTimelineEntries: 500, // Keep at most 500 entries in memory
|
|
889
|
+
});
|
|
781
890
|
```
|
|
782
891
|
|
|
783
892
|
### Procedures & Middleware
|
|
@@ -862,7 +971,79 @@ const result = await run(<MyApp />, {
|
|
|
862
971
|
await run(<Agent query="default" />, { props: { query: "override" }, model, messages });
|
|
863
972
|
```
|
|
864
973
|
|
|
865
|
-
`createApp` takes a component function and returns a reusable app with session management,
|
|
974
|
+
`createApp` takes a component function and returns a reusable app with session management, persistence, and middleware support.
|
|
975
|
+
|
|
976
|
+
## Execution Runners
|
|
977
|
+
|
|
978
|
+
An `ExecutionRunner` controls the execution backend — how compiled context reaches the model and how tool calls are routed. The default is the standard model → tool_use protocol. Swap in a different runner to change the entire execution model without touching your agent code.
|
|
979
|
+
|
|
980
|
+
```tsx
|
|
981
|
+
import { createApp, type ExecutionRunner } from "@agentick/core";
|
|
982
|
+
|
|
983
|
+
const replRunner: ExecutionRunner = {
|
|
984
|
+
name: "repl",
|
|
985
|
+
|
|
986
|
+
// Transform what the model sees — replace tool schemas with prose descriptions,
|
|
987
|
+
// expose a single "execute" tool, restructure sections, anything.
|
|
988
|
+
prepareModelInput(compiled, tools) {
|
|
989
|
+
const commandList = tools
|
|
990
|
+
.map((t) => `- ${t.metadata?.name}: ${t.metadata?.description}`)
|
|
991
|
+
.join("\n");
|
|
992
|
+
return {
|
|
993
|
+
...compiled,
|
|
994
|
+
tools: [executeToolSchema],
|
|
995
|
+
system: [...compiled.system, { content: `Available commands:\n${commandList}` }],
|
|
996
|
+
};
|
|
997
|
+
},
|
|
998
|
+
|
|
999
|
+
// Route tool calls — intercept "execute" to a sandbox, let others pass through.
|
|
1000
|
+
async executeToolCall(call, tool, next) {
|
|
1001
|
+
if (call.name === "execute") {
|
|
1002
|
+
return sandbox.run(call.input.code);
|
|
1003
|
+
}
|
|
1004
|
+
return next();
|
|
1005
|
+
},
|
|
1006
|
+
|
|
1007
|
+
// Session lifecycle
|
|
1008
|
+
onSessionInit(session) {
|
|
1009
|
+
sandbox.create(session.id);
|
|
1010
|
+
},
|
|
1011
|
+
onDestroy(session) {
|
|
1012
|
+
sandbox.destroy(session.id);
|
|
1013
|
+
},
|
|
1014
|
+
onPersist(session, snapshot) {
|
|
1015
|
+
return { ...snapshot, comState: { ...snapshot.comState, _sandbox: sandbox.state() } };
|
|
1016
|
+
},
|
|
1017
|
+
onRestore(session, snapshot) {
|
|
1018
|
+
sandbox.restore(snapshot.comState._sandbox);
|
|
1019
|
+
},
|
|
1020
|
+
};
|
|
1021
|
+
|
|
1022
|
+
// Same agent, different execution model
|
|
1023
|
+
const app = createApp(MyAgent, { model, runner: replRunner });
|
|
1024
|
+
```
|
|
1025
|
+
|
|
1026
|
+
The agent's JSX — its `<System>`, `<Timeline>`, `<Tool>` components — stays identical. The runner transforms how that compiled context is consumed and how tool calls execute. This means you can build one agent and run it against multiple backends: standard tool_use for production, a sandboxed REPL for code execution, a human-in-the-loop gateway for approval workflows.
|
|
1027
|
+
|
|
1028
|
+
### Interface
|
|
1029
|
+
|
|
1030
|
+
All methods are optional. Omitted methods use default behavior.
|
|
1031
|
+
|
|
1032
|
+
| Hook | Purpose | Timing |
|
|
1033
|
+
| ------------------- | --------------------------------------------------- | ------------- |
|
|
1034
|
+
| `prepareModelInput` | Transform compiled context before the model sees it | Per tick |
|
|
1035
|
+
| `executeToolCall` | Intercept, transform, or replace tool execution | Per tool call |
|
|
1036
|
+
| `onSessionInit` | Set up per-session resources (sandbox, workspace) | Once |
|
|
1037
|
+
| `onPersist` | Add runner state to session snapshot | Per save |
|
|
1038
|
+
| `onRestore` | Restore runner state from snapshot | Once |
|
|
1039
|
+
| `onDestroy` | Clean up resources | Once |
|
|
1040
|
+
|
|
1041
|
+
### Use Cases
|
|
1042
|
+
|
|
1043
|
+
- **REPL/Code Execution**: Replace tool schemas with command descriptions, route `execute` calls to a sandboxed runtime, persist sandbox state across sessions.
|
|
1044
|
+
- **Human-in-the-Loop**: Transform tool calls into approval requests, gate execution on human confirmation, log decisions.
|
|
1045
|
+
- **Sandboxing**: Run tools in isolated containers, inject security boundaries, audit tool invocations.
|
|
1046
|
+
- **Testing**: Intercept specific tools to return canned responses, track all lifecycle calls for assertions. See `createTestRunner()` in `@agentick/core/testing`.
|
|
866
1047
|
|
|
867
1048
|
## DevTools Integration
|
|
868
1049
|
|
|
@@ -889,6 +1070,24 @@ import { enableReactDevTools } from "@agentick/core";
|
|
|
889
1070
|
enableReactDevTools(); // Connects to npx react-devtools on port 8097
|
|
890
1071
|
```
|
|
891
1072
|
|
|
1073
|
+
## Local Transport
|
|
1074
|
+
|
|
1075
|
+
`createLocalTransport(app)` bridges an in-process `App` to the `ClientTransport` interface. This enables `@agentick/client` (and `@agentick/react` hooks) to work with a local app without any network layer.
|
|
1076
|
+
|
|
1077
|
+
```typescript
|
|
1078
|
+
import { createApp } from "@agentick/core";
|
|
1079
|
+
import { createLocalTransport } from "@agentick/core";
|
|
1080
|
+
import { createClient } from "@agentick/client";
|
|
1081
|
+
|
|
1082
|
+
const app = createApp(MyAgent, { model });
|
|
1083
|
+
const transport = createLocalTransport(app);
|
|
1084
|
+
const client = createClient({ baseUrl: "local://", transport });
|
|
1085
|
+
```
|
|
1086
|
+
|
|
1087
|
+
The transport is always "connected" — there's no network. `send()` delegates to `app.send()` and streams `SessionExecutionHandle` events as `TransportEventData`. Used by `@agentick/tui` for local agent mode.
|
|
1088
|
+
|
|
1089
|
+
See [`packages/shared/src/transport.ts`](../shared/src/transport.ts) for the `ClientTransport` interface.
|
|
1090
|
+
|
|
892
1091
|
## License
|
|
893
1092
|
|
|
894
1093
|
MIT
|