@arnilo/prism 0.5.6 → 0.7.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/CHANGELOG.md +81 -5
- package/README.md +10 -10
- package/dist/agent-approval.js +7 -6
- package/dist/agent-definitions.js +1 -0
- package/dist/agent-loops.js +51 -12
- package/dist/agent-run-lifecycle.js +11 -0
- package/dist/agent-run-state.d.ts +6 -0
- package/dist/agent-run-state.js +29 -9
- package/dist/agent-session/session/assemble.js +33 -2
- package/dist/agent-session/session/persist.js +6 -2
- package/dist/agent-session/session/tool-round.js +1 -0
- package/dist/agent-session/session/types.d.ts +10 -0
- package/dist/agent-session/session.d.ts +15 -0
- package/dist/agent-session/session.js +59 -4
- package/dist/agent-tool-dispatch.js +5 -4
- package/dist/artifacts.d.ts +39 -1
- package/dist/artifacts.js +73 -0
- package/dist/attention-compiler.d.ts +121 -0
- package/dist/attention-compiler.js +479 -0
- package/dist/cli-init.js +20 -6
- package/dist/content.d.ts +3 -16
- package/dist/content.js +9 -99
- package/dist/context-budget.d.ts +32 -2
- package/dist/context-budget.js +51 -19
- package/dist/contracts-core/agent.d.ts +18 -0
- package/dist/contracts-core/agent.js +4 -1
- package/dist/contracts-core/attention.d.ts +66 -0
- package/dist/contracts-core/attention.js +2 -0
- package/dist/contracts-core/compaction.d.ts +59 -0
- package/dist/contracts-core/compaction.js +77 -1
- package/dist/contracts-core/provider.d.ts +4 -0
- package/dist/contracts-core.d.ts +1 -0
- package/dist/contracts-core.js +1 -0
- package/dist/contracts-protocol.d.ts +29 -0
- package/dist/contracts-run-state.d.ts +6 -0
- package/dist/host-composition.d.ts +78 -0
- package/dist/host-composition.js +248 -0
- package/dist/index.d.ts +11 -8
- package/dist/index.js +6 -5
- package/dist/input.d.ts +19 -1
- package/dist/input.js +52 -2
- package/dist/media-types.d.ts +34 -0
- package/dist/media-types.js +158 -0
- package/dist/pinned-fetch.d.ts +2 -2
- package/dist/pinned-fetch.js +11 -12
- package/dist/redaction.js +74 -1
- package/dist/secure-agent.d.ts +2 -0
- package/dist/secure-agent.js +6 -1
- package/dist/session-stores.d.ts +11 -0
- package/dist/session-stores.js +23 -8
- package/dist/tool-result-fold.d.ts +12 -0
- package/dist/tool-result-fold.js +13 -6
- package/dist/tools.d.ts +10 -0
- package/dist/tools.js +41 -0
- package/docs/acp-agent.md +42 -11
- package/docs/acp.md +3 -2
- package/docs/ag-ui.md +9 -5
- package/docs/agent-definitions.md +9 -1
- package/docs/agent-events.md +6 -1
- package/docs/agent-loops.md +1 -1
- package/docs/agent-session-runtime.md +9 -7
- package/docs/attention-compiler.md +272 -0
- package/docs/browser-automation.md +5 -2
- package/docs/cli-rpc.md +4 -2
- package/docs/coding-agent-tools.md +1 -1
- package/docs/coding-security.md +5 -3
- package/docs/coding-tools.md +1 -1
- package/docs/coding-workspaces.md +22 -0
- package/docs/compaction-and-retry.md +36 -4
- package/docs/compaction-observational-memory.md +62 -9
- package/docs/context-and-skills.md +4 -2
- package/docs/contributing.md +37 -0
- package/docs/conversations.md +1 -1
- package/docs/core.md +2 -0
- package/docs/dev-inspector.md +4 -0
- package/docs/device-adapters.md +1 -0
- package/docs/document-reader.md +12 -2
- package/docs/documents.md +11 -3
- package/docs/enterprise-postgres-state.md +2 -2
- package/docs/evaluations.md +168 -4
- package/docs/execution-timeline.md +180 -0
- package/docs/graft.md +3 -1
- package/docs/history/0.7.0-primitive-review.md +254 -0
- package/docs/history/migration-0.0.md +2 -2
- package/docs/history/release-handoffs.md +70 -1
- package/docs/host-compositions.md +147 -0
- package/docs/host-security.md +2 -2
- package/docs/hosted-sandboxes.md +94 -0
- package/docs/index.md +73 -41
- package/docs/input-and-prompt-assembly.md +5 -4
- package/docs/knowledge-sync.md +84 -0
- package/docs/language-intelligence.md +2 -2
- package/docs/live-testing.md +4 -1
- package/docs/mcp-tools.md +2 -1
- package/docs/memory-fabric.md +416 -0
- package/docs/migrate-to-0.5.md +8 -3
- package/docs/migrate-to-0.6.md +90 -0
- package/docs/migrate-to-0.7.md +345 -0
- package/docs/migration.md +43 -1
- package/docs/model-registry.md +1 -1
- package/docs/model-routing.md +79 -4
- package/docs/multi-agent-patterns.md +20 -6
- package/docs/multimodal-content.md +1 -1
- package/docs/obscura.md +3 -1
- package/docs/observability.md +52 -1
- package/docs/operations.md +13 -1
- package/docs/options-index.md +298 -0
- package/docs/peer-dependencies.md +96 -0
- package/docs/performance.md +34 -2
- package/docs/ponytail.md +2 -0
- package/docs/postgres-persistence.md +3 -1
- package/docs/process-sessions.md +3 -1
- package/docs/prompt-registry.md +1 -1
- package/docs/provider-caching.md +4 -2
- package/docs/provider-conformance.md +2 -2
- package/docs/provider-packages.md +23 -23
- package/docs/provider-primitives.md +2 -1
- package/docs/providers/ai-sdk.md +5 -2
- package/docs/providers/bedrock.md +71 -7
- package/docs/providers/openai.md +1 -1
- package/docs/public-contracts.md +2 -2
- package/docs/rag.md +24 -8
- package/docs/realtime-voice.md +87 -0
- package/docs/release-and-install.md +78 -56
- package/docs/runs-and-usage.md +3 -2
- package/docs/server.md +6 -4
- package/docs/session-stores.md +3 -1
- package/docs/speech.md +2 -0
- package/docs/sqlite-persistence.md +2 -0
- package/docs/supervisors.md +33 -5
- package/docs/testing.md +38 -0
- package/docs/thinking-and-reasoning.md +3 -1
- package/docs/tools.md +7 -6
- package/docs/web-tools.md +2 -1
- package/docs/wiki.md +1 -1
- package/docs/work-artifacts-and-review.md +14 -4
- package/docs/work-connectors.md +3 -1
- package/docs/work-tools.md +14 -4
- package/docs/workflows.md +69 -1
- package/docs/working-and-semantic-memory.md +25 -14
- package/package.json +5 -5
- package/templates/README.md +2 -0
- package/templates/business-worker/README.md.tmpl +19 -0
- package/templates/business-worker/env.example.tmpl +1 -0
- package/templates/business-worker/gitignore.tmpl +11 -0
- package/templates/business-worker/manifest.json +11 -0
- package/templates/business-worker/package.json.tmpl +23 -0
- package/templates/business-worker/src/agent.ts.tmpl +92 -0
- package/templates/business-worker/src/index.ts.tmpl +13 -0
- package/templates/business-worker/src/tests/agent.test.ts.tmpl +77 -0
- package/templates/business-worker/tsconfig.json.tmpl +15 -0
- package/templates/personal-assistant/README.md.tmpl +18 -0
- package/templates/personal-assistant/env.example.tmpl +1 -0
- package/templates/personal-assistant/gitignore.tmpl +11 -0
- package/templates/personal-assistant/manifest.json +11 -0
- package/templates/personal-assistant/package.json.tmpl +23 -0
- package/templates/personal-assistant/src/agent.ts.tmpl +65 -0
- package/templates/personal-assistant/src/index.ts.tmpl +13 -0
- package/templates/personal-assistant/src/tests/agent.test.ts.tmpl +28 -0
- package/templates/personal-assistant/tsconfig.json.tmpl +15 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arnilo/prism",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Agent harness for AI providers, agents, sessions, and tools.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -139,7 +139,7 @@
|
|
|
139
139
|
"typecheck": "npm run build && npm run typecheck --workspaces --if-present && tsc -p examples --noEmit",
|
|
140
140
|
"sweep:unused": "node scripts/sweep-unused.mjs --json",
|
|
141
141
|
"test:live": "node scripts/live-matrix.mjs",
|
|
142
|
-
"test": "
|
|
142
|
+
"test": "node scripts/run-all-tests.mjs",
|
|
143
143
|
"test:coverage": "node scripts/with-build-lock.mjs node --test --experimental-test-coverage --test-coverage-lines=60 --test-coverage-functions=70 --test-coverage-branches=75 --test-coverage-exclude='**/__tests__/**' --test-coverage-exclude='**/node_modules/**' --test-coverage-exclude='**/scripts/**' --test-coverage-exclude='**/packages/**' --test-coverage-exclude='**/examples/**' dist/__tests__/*.test.js && node scripts/with-build-lock.mjs node scripts/coverage-summary.mjs && node --test scripts/phase23-coverage.test.mjs && node --test scripts/phase23-skip-manifest.test.mjs",
|
|
144
144
|
"coverage:summary": "node scripts/with-build-lock.mjs node scripts/coverage-summary.mjs",
|
|
145
145
|
"lint": "biome lint . --reporter=sarif --reporter-file=scripts/lint-report.sarif",
|
|
@@ -157,12 +157,12 @@
|
|
|
157
157
|
"security:threat-suites": "node --test scripts/phase8-conformance.test.mjs scripts/phase9-conformance.test.mjs scripts/phase10-conformance.test.mjs scripts/phase11-conformance.test.mjs scripts/phase20-security.test.mjs scripts/phase21-security.test.mjs scripts/phase22-security.test.mjs scripts/phase23-security.test.mjs scripts/phase38-codeql-regression.test.mjs scripts/phase40-security.test.mjs scripts/phase46-webhooks-security.test.mjs dist/__tests__/pinned-fetch.test.js packages/prism-core/dist/runtime/server/__tests__/webhooks.test.js"
|
|
158
158
|
},
|
|
159
159
|
"devDependencies": {
|
|
160
|
-
"@biomejs/biome": "^2.5.
|
|
161
|
-
"@types/node": "^
|
|
160
|
+
"@biomejs/biome": "^2.5.13",
|
|
161
|
+
"@types/node": "^22.20.0",
|
|
162
162
|
"typescript": "^7.0.2"
|
|
163
163
|
},
|
|
164
164
|
"engines": {
|
|
165
|
-
"node": ">=
|
|
165
|
+
"node": ">=22"
|
|
166
166
|
},
|
|
167
167
|
"license": "MIT",
|
|
168
168
|
"repository": {
|
package/templates/README.md
CHANGED
|
@@ -8,6 +8,8 @@ Ready-to-run project templates for `prism init --template <name>`.
|
|
|
8
8
|
| --- | --- | --- |
|
|
9
9
|
| `init` | Minimal starter Prism agent with one selected provider and offline mock test | `@arnilo/prism` |
|
|
10
10
|
| `deep-research` | Flagship deep research agent: plan -> search -> extract -> refine loop -> citations -> HITL clarify | `@arnilo/prism`, `@arnilo/prism-web-tools`, `@arnilo/prism-memory`, `@arnilo/prism-workflows` |
|
|
11
|
+
| `personal-assistant` | Personal workstation assistant: single-user ownership, local tools, credential references, and dev inspection | `@arnilo/prism`, `@arnilo/prism-core`, `@arnilo/prism-providers` |
|
|
12
|
+
| `business-worker` | Multi-tenant business worker: durable storage, tenant isolation, verified identity, and governed boundaries | `@arnilo/prism`, `@arnilo/prism-core`, `@arnilo/prism-providers` |
|
|
11
13
|
|
|
12
14
|
## Usage
|
|
13
15
|
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# __PROJECT_NAME__
|
|
2
|
+
|
|
3
|
+
Multi-tenant business worker built with Prism. Features strict tenant isolation, verified identities, durable persistence, and governed invocation boundaries.
|
|
4
|
+
|
|
5
|
+
## Quickstart
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install
|
|
9
|
+
npm test
|
|
10
|
+
npm start
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Production Readiness Requirements
|
|
14
|
+
|
|
15
|
+
- **Tenant Isolation**: Non-empty `tenantId` in ownership; tenant-scoped stores and workspaces.
|
|
16
|
+
- **Verified Identity**: Host-verified principal matching tenant ownership; no fabricated identities.
|
|
17
|
+
- **Durable Persistence**: Production readiness strictly rejects in-memory stores; PostgreSQL or SQLite durable stores required.
|
|
18
|
+
- **Workspace Containment**: Execution confined to authorized tenant sandbox directories.
|
|
19
|
+
- **Governed Invocation**: Permission policies, trust verification, parameter validation, and secret redaction enforced.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
BUSINESS_API_KEY=
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "business-worker",
|
|
3
|
+
"description": "Multi-tenant business worker: durable storage, tenant isolation, verified identity, and governed invocation boundaries",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"tags": ["business", "worker", "multi-tenant", "enterprise", "secure"],
|
|
6
|
+
"packages": [
|
|
7
|
+
"@arnilo/prism",
|
|
8
|
+
"@arnilo/prism-core",
|
|
9
|
+
"@arnilo/prism-providers"
|
|
10
|
+
]
|
|
11
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "__PROJECT_NAME__",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"build": "tsc -p tsconfig.json",
|
|
8
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
9
|
+
"test": "npm run build && node --test dist/__tests__/agent.test.js",
|
|
10
|
+
"start": "npm run build && node dist/index.js",
|
|
11
|
+
"dev": "prism dev"
|
|
12
|
+
},
|
|
13
|
+
"dependencies": {
|
|
14
|
+
__DEPENDENCIES__
|
|
15
|
+
},
|
|
16
|
+
"devDependencies": {
|
|
17
|
+
"@types/node": "^22.0.0",
|
|
18
|
+
"typescript": "^5.7.0"
|
|
19
|
+
},
|
|
20
|
+
"engines": {
|
|
21
|
+
"node": ">=20"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type Agent,
|
|
3
|
+
createMemoryCheckpointStore,
|
|
4
|
+
createMockProvider,
|
|
5
|
+
createSecretRedactor,
|
|
6
|
+
createSecureAgent,
|
|
7
|
+
createStaticPermissionPolicy,
|
|
8
|
+
createStaticTrustPolicy,
|
|
9
|
+
providerDone,
|
|
10
|
+
providerTextDelta,
|
|
11
|
+
} from "@arnilo/prism";
|
|
12
|
+
import { createJsonSchemaArgumentValidator } from "@arnilo/prism-core/validation/json-schema";
|
|
13
|
+
import { createMemoryWorkDraftStore, type SyncWorkDraftStore } from "@arnilo/prism-core/integrations/work";
|
|
14
|
+
import type { AgentIdentity } from "@arnilo/prism";
|
|
15
|
+
|
|
16
|
+
export interface CreateBusinessWorkerOptions {
|
|
17
|
+
readonly tenantId?: string;
|
|
18
|
+
readonly userId?: string;
|
|
19
|
+
readonly identity?: AgentIdentity;
|
|
20
|
+
readonly store?: import("@arnilo/prism").CheckpointStore;
|
|
21
|
+
readonly provider?: import("@arnilo/prism").AIProvider;
|
|
22
|
+
readonly model?: { readonly provider: string; readonly model: string };
|
|
23
|
+
readonly workspaceRoot?: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function createAppAgent(options: CreateBusinessWorkerOptions = {}): Agent {
|
|
27
|
+
const tenantId = options.tenantId ?? "tenant-corp";
|
|
28
|
+
const userId = options.userId ?? "worker-1";
|
|
29
|
+
|
|
30
|
+
const identity: AgentIdentity = options.identity ?? {
|
|
31
|
+
tenantId,
|
|
32
|
+
userId,
|
|
33
|
+
principal: { kind: "user", id: userId },
|
|
34
|
+
scopes: ["worker:execute"],
|
|
35
|
+
verified: true,
|
|
36
|
+
issuedAt: new Date().toISOString(),
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const redactor = createSecretRedactor(
|
|
40
|
+
[process.env.BUSINESS_API_KEY].filter((v): v is string => typeof v === "string" && v.length > 0),
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
const provider =
|
|
44
|
+
options.provider ??
|
|
45
|
+
createMockProvider([
|
|
46
|
+
providerTextDelta("Business worker ready for tenant tasks."),
|
|
47
|
+
providerDone(),
|
|
48
|
+
]);
|
|
49
|
+
|
|
50
|
+
return createSecureAgent({
|
|
51
|
+
id: "business-worker",
|
|
52
|
+
definitionRevision: "1",
|
|
53
|
+
ownership: { tenantId, userId },
|
|
54
|
+
identity,
|
|
55
|
+
redactor,
|
|
56
|
+
permission: createStaticPermissionPolicy(true),
|
|
57
|
+
trust: createStaticTrustPolicy(true),
|
|
58
|
+
toolArgumentValidator: createJsonSchemaArgumentValidator(),
|
|
59
|
+
limits: { maxToolRounds: 15 },
|
|
60
|
+
runState: { checkpoints: options.store ?? createMemoryCheckpointStore() },
|
|
61
|
+
tools: [
|
|
62
|
+
{
|
|
63
|
+
name: "process_tenant_record",
|
|
64
|
+
description: "Processes a verified tenant batch item",
|
|
65
|
+
parameters: {
|
|
66
|
+
type: "object",
|
|
67
|
+
properties: {
|
|
68
|
+
recordId: { type: "string" },
|
|
69
|
+
action: { type: "string" },
|
|
70
|
+
},
|
|
71
|
+
required: ["recordId", "action"],
|
|
72
|
+
additionalProperties: false,
|
|
73
|
+
},
|
|
74
|
+
execute: async (args, ctx) => ({
|
|
75
|
+
toolCallId: ctx.toolCallId,
|
|
76
|
+
name: "process_tenant_record",
|
|
77
|
+
value: {
|
|
78
|
+
processed: true,
|
|
79
|
+
tenantId,
|
|
80
|
+
recordId: (args as { recordId: string }).recordId,
|
|
81
|
+
},
|
|
82
|
+
}),
|
|
83
|
+
},
|
|
84
|
+
],
|
|
85
|
+
provider,
|
|
86
|
+
model: options.model ?? { provider: "mock", model: "corp-worker-model" },
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export function createWorkerDraftStore(): SyncWorkDraftStore {
|
|
91
|
+
return createMemoryWorkDraftStore();
|
|
92
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { createAppAgent } from "./agent.js";
|
|
2
|
+
|
|
3
|
+
async function main() {
|
|
4
|
+
const agent = createAppAgent({ tenantId: "tenant-acme", userId: "worker-prod-1" });
|
|
5
|
+
const session = agent.createSession({ id: "biz-session-1" });
|
|
6
|
+
const result = await session.run("Process batch queue item");
|
|
7
|
+
console.log(result.text);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
main().catch((error) => {
|
|
11
|
+
console.error("Business worker failed:", error);
|
|
12
|
+
process.exit(1);
|
|
13
|
+
});
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { describe, it } from "node:test";
|
|
3
|
+
import { assertHostCompositionReadiness, inspectHostComposition, HostCompositionError } from "@arnilo/prism";
|
|
4
|
+
import { validateApproval } from "@arnilo/prism-core/integrations/work";
|
|
5
|
+
import type { AgentIdentity } from "@arnilo/prism";
|
|
6
|
+
import { createAppAgent, createWorkerDraftStore } from "../agent.js";
|
|
7
|
+
|
|
8
|
+
describe("business worker template", () => {
|
|
9
|
+
it("creates agent and processes task with tenant context", async () => {
|
|
10
|
+
const agent = createAppAgent({ tenantId: "tenant-enterprise", userId: "worker-test" });
|
|
11
|
+
const session = agent.createSession({ id: "test-biz-session" });
|
|
12
|
+
const result = await session.run("Run tenant task");
|
|
13
|
+
assert.ok(result.text.includes("Business worker ready"));
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it("fails business readiness if memory-only store is configured", () => {
|
|
17
|
+
const agent = createAppAgent({ tenantId: "tenant-enterprise", userId: "worker-test" });
|
|
18
|
+
assert.throws(
|
|
19
|
+
() => {
|
|
20
|
+
assertHostCompositionReadiness({
|
|
21
|
+
profile: "business",
|
|
22
|
+
agent,
|
|
23
|
+
store: { kind: "memory", durable: false },
|
|
24
|
+
});
|
|
25
|
+
},
|
|
26
|
+
(error) => error instanceof HostCompositionError && error.message.includes("durable storage"),
|
|
27
|
+
);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("passes business readiness with durable store and isolated workspace", () => {
|
|
31
|
+
const agent = createAppAgent({ tenantId: "tenant-enterprise", userId: "worker-test" });
|
|
32
|
+
const report = inspectHostComposition({
|
|
33
|
+
profile: "business",
|
|
34
|
+
agent,
|
|
35
|
+
store: { kind: "postgres", durable: true },
|
|
36
|
+
workspaceRoot: "/var/tenant-enterprise",
|
|
37
|
+
sandboxRoots: ["/var/tenant-enterprise/tasks"],
|
|
38
|
+
credentialRefs: ["BUSINESS_API_KEY"],
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
assert.equal(report.profile, "business");
|
|
42
|
+
assert.equal(report.ownership.tenantId, "tenant-enterprise");
|
|
43
|
+
assert.equal(report.storage.durable, true);
|
|
44
|
+
assert.equal(report.sandbox.isolated, true);
|
|
45
|
+
assert.equal(report.readiness.ok, true);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it("rejects a stale draft revision after edit", () => {
|
|
49
|
+
const store = createWorkerDraftStore();
|
|
50
|
+
const identity: AgentIdentity = {
|
|
51
|
+
tenantId: "tenant-enterprise",
|
|
52
|
+
userId: "worker-test",
|
|
53
|
+
principal: { kind: "user", id: "worker-test" },
|
|
54
|
+
scopes: ["Mail.Send"],
|
|
55
|
+
issuedAt: new Date().toISOString(),
|
|
56
|
+
verified: true,
|
|
57
|
+
};
|
|
58
|
+
const draft = store.createDraft({
|
|
59
|
+
provider: "microsoft365",
|
|
60
|
+
op: "mail.send",
|
|
61
|
+
identity,
|
|
62
|
+
payload: { to: "a@contoso.com", subject: "v1" },
|
|
63
|
+
});
|
|
64
|
+
const approval = {
|
|
65
|
+
draftId: draft.draftId,
|
|
66
|
+
revision: draft.revision,
|
|
67
|
+
payloadDigest: draft.payloadDigest,
|
|
68
|
+
};
|
|
69
|
+
const updated = store.updateDraft({
|
|
70
|
+
draftId: draft.draftId,
|
|
71
|
+
identity,
|
|
72
|
+
payload: { to: "a@contoso.com", subject: "v2" },
|
|
73
|
+
expectedRevision: 1,
|
|
74
|
+
});
|
|
75
|
+
assert.throws(() => validateApproval(updated, approval), /does not match draft revision/);
|
|
76
|
+
});
|
|
77
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "NodeNext",
|
|
5
|
+
"moduleResolution": "NodeNext",
|
|
6
|
+
"strict": true,
|
|
7
|
+
"outDir": "dist",
|
|
8
|
+
"rootDir": "src",
|
|
9
|
+
"declaration": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"esModuleInterop": true,
|
|
12
|
+
"forceConsistentCasingInFileNames": true
|
|
13
|
+
},
|
|
14
|
+
"include": ["src"]
|
|
15
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# __PROJECT_NAME__
|
|
2
|
+
|
|
3
|
+
Personal workstation assistant built with Prism. Features single-user ownership, local tools, credential references, and loopback dev inspection.
|
|
4
|
+
|
|
5
|
+
## Quickstart
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install
|
|
9
|
+
npm test
|
|
10
|
+
npm run dev # Boots loopback dev inspector at http://127.0.0.1:4311
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Security Posture
|
|
14
|
+
|
|
15
|
+
- **Single-User Ownership**: Bounded to the local workstation operator (`userId: process.env.USER`).
|
|
16
|
+
- **Secret Redaction**: Environment secrets are redacted before persistence or logs.
|
|
17
|
+
- **Durable Verification**: Uses memory/local storage; in-memory storage is recognized as non-durable.
|
|
18
|
+
- **Containment**: Tool actions are contained to local workspace roots.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
OPENAI_API_KEY=
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "personal-assistant",
|
|
3
|
+
"description": "Personal workstation assistant: local single-user agent with file tools, credential references, and loopback dev inspection",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"tags": ["personal", "workstation", "assistant", "local", "secure"],
|
|
6
|
+
"packages": [
|
|
7
|
+
"@arnilo/prism",
|
|
8
|
+
"@arnilo/prism-core",
|
|
9
|
+
"@arnilo/prism-providers"
|
|
10
|
+
]
|
|
11
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "__PROJECT_NAME__",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"build": "tsc -p tsconfig.json",
|
|
8
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
9
|
+
"test": "npm run build && node --test dist/__tests__/agent.test.js",
|
|
10
|
+
"start": "npm run build && node dist/index.js",
|
|
11
|
+
"dev": "prism dev"
|
|
12
|
+
},
|
|
13
|
+
"dependencies": {
|
|
14
|
+
__DEPENDENCIES__
|
|
15
|
+
},
|
|
16
|
+
"devDependencies": {
|
|
17
|
+
"@types/node": "^22.0.0",
|
|
18
|
+
"typescript": "^5.7.0"
|
|
19
|
+
},
|
|
20
|
+
"engines": {
|
|
21
|
+
"node": ">=20"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type Agent,
|
|
3
|
+
createMemoryCheckpointStore,
|
|
4
|
+
createMockProvider,
|
|
5
|
+
createSecretRedactor,
|
|
6
|
+
createSecureAgent,
|
|
7
|
+
createStaticPermissionPolicy,
|
|
8
|
+
createStaticTrustPolicy,
|
|
9
|
+
providerDone,
|
|
10
|
+
providerTextDelta,
|
|
11
|
+
} from "@arnilo/prism";
|
|
12
|
+
import { createJsonSchemaArgumentValidator } from "@arnilo/prism-core/validation/json-schema";
|
|
13
|
+
|
|
14
|
+
export interface CreatePersonalAgentOptions {
|
|
15
|
+
readonly userId?: string;
|
|
16
|
+
readonly provider?: import("@arnilo/prism").AIProvider;
|
|
17
|
+
readonly model?: { readonly provider: string; readonly model: string };
|
|
18
|
+
readonly workspaceRoot?: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function createAppAgent(options: CreatePersonalAgentOptions = {}): Agent {
|
|
22
|
+
const userId = options.userId ?? process.env.USER ?? "local-user";
|
|
23
|
+
const redactor = createSecretRedactor(
|
|
24
|
+
[process.env.OPENAI_API_KEY].filter((v): v is string => typeof v === "string" && v.length > 0),
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
const provider =
|
|
28
|
+
options.provider ??
|
|
29
|
+
createMockProvider([
|
|
30
|
+
providerTextDelta("Personal Assistant ready. How can I help you today?"),
|
|
31
|
+
providerDone(),
|
|
32
|
+
]);
|
|
33
|
+
|
|
34
|
+
return createSecureAgent({
|
|
35
|
+
id: "personal-assistant",
|
|
36
|
+
definitionRevision: "1",
|
|
37
|
+
ownership: { userId },
|
|
38
|
+
redactor,
|
|
39
|
+
permission: createStaticPermissionPolicy(true),
|
|
40
|
+
trust: createStaticTrustPolicy(true),
|
|
41
|
+
toolArgumentValidator: createJsonSchemaArgumentValidator(),
|
|
42
|
+
limits: { maxToolRounds: 10 },
|
|
43
|
+
runState: { checkpoints: createMemoryCheckpointStore() },
|
|
44
|
+
tools: [
|
|
45
|
+
{
|
|
46
|
+
name: "workspace_status",
|
|
47
|
+
description: "Reports the local workspace status and configuration",
|
|
48
|
+
parameters: {
|
|
49
|
+
type: "object",
|
|
50
|
+
properties: {
|
|
51
|
+
details: { type: "boolean", description: "Include detailed status" },
|
|
52
|
+
},
|
|
53
|
+
additionalProperties: false,
|
|
54
|
+
},
|
|
55
|
+
execute: async (_args, ctx) => ({
|
|
56
|
+
toolCallId: ctx.toolCallId,
|
|
57
|
+
name: "workspace_status",
|
|
58
|
+
value: { ok: true, user: userId, status: "active" },
|
|
59
|
+
}),
|
|
60
|
+
},
|
|
61
|
+
],
|
|
62
|
+
provider,
|
|
63
|
+
model: options.model ?? { provider: "mock", model: "personal-default" },
|
|
64
|
+
});
|
|
65
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { createAppAgent } from "./agent.js";
|
|
2
|
+
|
|
3
|
+
async function main() {
|
|
4
|
+
const agent = createAppAgent();
|
|
5
|
+
const session = agent.createSession({ id: "personal-session-1" });
|
|
6
|
+
const result = await session.run("Check workspace status");
|
|
7
|
+
console.log(result.text);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
main().catch((error) => {
|
|
11
|
+
console.error("Personal assistant failed:", error);
|
|
12
|
+
process.exit(1);
|
|
13
|
+
});
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { describe, it } from "node:test";
|
|
3
|
+
import { assertHostCompositionReadiness, inspectHostComposition } from "@arnilo/prism";
|
|
4
|
+
import { createAppAgent } from "../agent.js";
|
|
5
|
+
|
|
6
|
+
describe("personal assistant template", () => {
|
|
7
|
+
it("creates agent and runs an offline turn", async () => {
|
|
8
|
+
const agent = createAppAgent({ userId: "test-user" });
|
|
9
|
+
const session = agent.createSession({ id: "test-session" });
|
|
10
|
+
const result = await session.run("Hello");
|
|
11
|
+
assert.ok(result.text.includes("Personal Assistant ready"));
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it("passes personal host composition readiness inspection", () => {
|
|
15
|
+
const agent = createAppAgent({ userId: "test-user" });
|
|
16
|
+
const report = inspectHostComposition({
|
|
17
|
+
profile: "personal",
|
|
18
|
+
agent,
|
|
19
|
+
credentialRefs: ["OPENAI_API_KEY"],
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
assert.equal(report.profile, "personal");
|
|
23
|
+
assert.equal(report.ownership.userId, "test-user");
|
|
24
|
+
assert.equal(report.readiness.ok, true);
|
|
25
|
+
assert.equal(report.storage.durable, false, "in-memory store is non-durable");
|
|
26
|
+
assert.doesNotThrow(() => assertHostCompositionReadiness({ profile: "personal", agent }));
|
|
27
|
+
});
|
|
28
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "NodeNext",
|
|
5
|
+
"moduleResolution": "NodeNext",
|
|
6
|
+
"strict": true,
|
|
7
|
+
"outDir": "dist",
|
|
8
|
+
"rootDir": "src",
|
|
9
|
+
"declaration": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"esModuleInterop": true,
|
|
12
|
+
"forceConsistentCasingInFileNames": true
|
|
13
|
+
},
|
|
14
|
+
"include": ["src"]
|
|
15
|
+
}
|