@stackbone/cli 0.7.0 → 0.8.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 +147 -0
- package/main.js +14724 -11224
- package/migrations/0114_memory_person_id.sql +16 -0
- package/migrations/0115_memory_erased_person_keeps_no_identifier.sql +31 -0
- package/migrations/0116_rag_hybrid_search.sql +14 -0
- package/migrations/0117_rag_extract_fields.sql +3 -0
- package/migrations/0118_voice_outbound_calls.sql +29 -0
- package/migrations/0119_voice_call_metrics.sql +20 -0
- package/migrations/0120_run_steps_voice.sql +19 -0
- package/migrations/0121_model_routing.sql +28 -0
- package/package.json +1 -1
- package/stackbone-cli-0.8.0.tgz +0 -0
- package/voice-worker/main.js +299 -51
- package/voice-worker/main.js.map +4 -4
- package/stackbone-cli-0.7.0.tgz +0 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
-- STA3-33: Studio and the box address a person by this opaque per-agent id
|
|
2
|
+
-- instead of the phone or email in user_id, which leaked into URLs and logs.
|
|
3
|
+
-- It lives on the revision row because an erase bumps the revision and keeps
|
|
4
|
+
-- the row, so a person who is deleted and comes back keeps the same id.
|
|
5
|
+
|
|
6
|
+
ALTER TABLE stackbone_platform.memory_user_revisions
|
|
7
|
+
ADD COLUMN person_id uuid NOT NULL DEFAULT gen_random_uuid(),
|
|
8
|
+
ADD CONSTRAINT memory_user_revisions_person_id_key UNIQUE (person_id);
|
|
9
|
+
|
|
10
|
+
-- A person with facts or calls but no revision row yet has no id to open.
|
|
11
|
+
INSERT INTO stackbone_platform.memory_user_revisions (agent_id, user_id, revision)
|
|
12
|
+
SELECT agent_id, user_id, 0 FROM (
|
|
13
|
+
SELECT agent_id, user_id FROM stackbone_platform.memory_facts
|
|
14
|
+
UNION SELECT agent_id, user_id FROM stackbone_platform.memory_calls
|
|
15
|
+
) AS people
|
|
16
|
+
ON CONFLICT (agent_id, user_id) DO NOTHING;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
-- STA3-35: an erase keeps the revision row as a tombstone, so an add that
|
|
2
|
+
-- snapshotted before the erase still fails its revision check and cannot write
|
|
3
|
+
-- the erased memory back. The tombstone kept the phone or email in user_id; it
|
|
4
|
+
-- now keeps only the opaque person_id, so user_id is nullable and person_id is
|
|
5
|
+
-- the key. UNIQUE (agent_id, user_id) stays the lookup the SDK's
|
|
6
|
+
-- ON CONFLICT (agent_id, user_id) infers, and Postgres treats NULLs as
|
|
7
|
+
-- distinct, so an agent can hold many erased rows.
|
|
8
|
+
|
|
9
|
+
ALTER TABLE stackbone_platform.memory_user_revisions
|
|
10
|
+
DROP CONSTRAINT memory_user_revisions_pkey;
|
|
11
|
+
ALTER TABLE stackbone_platform.memory_user_revisions
|
|
12
|
+
ALTER COLUMN user_id DROP NOT NULL,
|
|
13
|
+
ADD CONSTRAINT memory_user_revisions_pkey PRIMARY KEY (person_id),
|
|
14
|
+
DROP CONSTRAINT memory_user_revisions_person_id_key,
|
|
15
|
+
ADD CONSTRAINT memory_user_revisions_agent_id_user_id_key UNIQUE (agent_id, user_id);
|
|
16
|
+
|
|
17
|
+
-- People erased before this change. Only an erase deletes memory_calls, and
|
|
18
|
+
-- every committed add writes a call with its revision bump, so a row with no
|
|
19
|
+
-- facts and no calls on its own agent is an erased tombstone. The rule holds
|
|
20
|
+
-- only here: once adds claim the row at snapshot, a failed add can leave such
|
|
21
|
+
-- a row for a live person.
|
|
22
|
+
UPDATE stackbone_platform.memory_user_revisions AS revisions
|
|
23
|
+
SET user_id = NULL
|
|
24
|
+
WHERE NOT EXISTS (
|
|
25
|
+
SELECT 1 FROM stackbone_platform.memory_facts AS facts
|
|
26
|
+
WHERE facts.agent_id = revisions.agent_id AND facts.user_id = revisions.user_id
|
|
27
|
+
)
|
|
28
|
+
AND NOT EXISTS (
|
|
29
|
+
SELECT 1 FROM stackbone_platform.memory_calls AS calls
|
|
30
|
+
WHERE calls.agent_id = revisions.agent_id AND calls.user_id = revisions.user_id
|
|
31
|
+
);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
-- STA3-57: lexical + hybrid search, opt-in per collection.
|
|
2
|
+
ALTER TABLE stackbone_platform.rag_collections
|
|
3
|
+
ADD COLUMN IF NOT EXISTS hybrid_enabled boolean NOT NULL DEFAULT false,
|
|
4
|
+
ADD COLUMN IF NOT EXISTS number_format text NOT NULL DEFAULT 'eu'
|
|
5
|
+
CONSTRAINT rag_collections_number_format_check CHECK (number_format IN ('eu', 'us'));
|
|
6
|
+
|
|
7
|
+
-- Nullable: ingest writes the terms only while the collection has hybrid on
|
|
8
|
+
-- (STA3-57 D11). The terms are normalised in TypeScript, so no `unaccent` (D6).
|
|
9
|
+
ALTER TABLE stackbone_platform.rag_chunks
|
|
10
|
+
ADD COLUMN IF NOT EXISTS lexical tsvector;
|
|
11
|
+
|
|
12
|
+
-- Built under the migrator's advisory lock, like the 1536 index in 0103.
|
|
13
|
+
CREATE INDEX IF NOT EXISTS rag_chunks_lexical_gin
|
|
14
|
+
ON stackbone_platform.rag_chunks USING gin (lexical);
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
-- 0118_voice_outbound_calls.sql — the answered outbound calls a workflow placed
|
|
2
|
+
-- (`placeCall`, STA3-56) whose `onEnd` workflow has not started yet.
|
|
3
|
+
--
|
|
4
|
+
-- A row is written when the callee answers and deleted once `onEnd` has started,
|
|
5
|
+
-- so the table holds only live calls and the phone number never outlives the
|
|
6
|
+
-- call. It lives in Postgres, not in the box's memory, because the fallback that
|
|
7
|
+
-- starts `onEnd` for a worker that never posts its completion must also cover a
|
|
8
|
+
-- box that restarted mid-call.
|
|
9
|
+
--
|
|
10
|
+
-- `claimed_at` is the once-only guard: whoever sets it from NULL (the worker's
|
|
11
|
+
-- `/complete` or the sweep) starts `onEnd`. A claim older than the sweep's
|
|
12
|
+
-- reclaim window belongs to a box that died between the claim and the start, and
|
|
13
|
+
-- may be taken again. `room_gone_at` is when the sweep first saw the LiveKit room
|
|
14
|
+
-- gone; the sweep gives the worker a grace period after it before it ends the
|
|
15
|
+
-- call as `failed`.
|
|
16
|
+
--
|
|
17
|
+
-- `context` is what the workflow passed to `placeCall`, opaque to the box and
|
|
18
|
+
-- never logged.
|
|
19
|
+
CREATE TABLE IF NOT EXISTS stackbone_platform.voice_outbound_calls (
|
|
20
|
+
session_key text PRIMARY KEY,
|
|
21
|
+
room text NOT NULL,
|
|
22
|
+
agent text NOT NULL,
|
|
23
|
+
to_number text NOT NULL,
|
|
24
|
+
context jsonb NOT NULL,
|
|
25
|
+
on_end text NOT NULL,
|
|
26
|
+
answered_at timestamptz NOT NULL,
|
|
27
|
+
room_gone_at timestamptz NULL,
|
|
28
|
+
claimed_at timestamptz NULL
|
|
29
|
+
);
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
-- 0119_voice_call_metrics.sql — the latencies of each answered turn of a voice call,
|
|
2
|
+
-- as LiveKit measured them in the voice worker (STA3-56).
|
|
3
|
+
--
|
|
4
|
+
-- The worker sends them once, with the transcript, in the call's `/complete`; the
|
|
5
|
+
-- box writes one row per call and never updates it. It is keyed by the call's
|
|
6
|
+
-- session id, the same one `voice_recordings` uses, so a screen that shows a call
|
|
7
|
+
-- finds its recording and its latencies by one id. A second `/complete` of the same
|
|
8
|
+
-- call shares the first one's result, so the row cannot be written twice; the
|
|
9
|
+
-- insert still skips a conflict rather than fail a completion over a duplicate.
|
|
10
|
+
--
|
|
11
|
+
-- `turns` is the worker's array as the box validated it
|
|
12
|
+
-- (`voiceCallTurnMetricsSchema`): numbers only, no transcript text and nothing that
|
|
13
|
+
-- names the caller, which is why the memory erase does not touch this table.
|
|
14
|
+
CREATE TABLE IF NOT EXISTS stackbone_platform.voice_call_metrics (
|
|
15
|
+
session_id uuid PRIMARY KEY,
|
|
16
|
+
agent text NOT NULL,
|
|
17
|
+
session_key text NOT NULL,
|
|
18
|
+
turns jsonb NOT NULL,
|
|
19
|
+
created_at timestamptz NOT NULL DEFAULT now()
|
|
20
|
+
);
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
-- 0120_run_steps_voice.sql — a `voice` step: one phase of how long a voice turn made
|
|
2
|
+
-- its caller wait (STA3-56).
|
|
3
|
+
--
|
|
4
|
+
-- The voice worker measures each answered turn with LiveKit (end of turn, speech to
|
|
5
|
+
-- text, the agent's first token, speech synthesis, and the whole wait) and sends the
|
|
6
|
+
-- numbers once, in the call's `/complete`. The box then writes them as steps on the
|
|
7
|
+
-- run that answered the turn, so the run's trace shows them on the same time axis
|
|
8
|
+
-- as its `model_call`: a `Wait` parent and one child per phase. Their times come
|
|
9
|
+
-- from the run's own start, the box's clock, so a worker clock that drifts never
|
|
10
|
+
-- moves them.
|
|
11
|
+
ALTER TABLE stackbone_platform.run_steps
|
|
12
|
+
DROP CONSTRAINT IF EXISTS run_steps_type_check;
|
|
13
|
+
|
|
14
|
+
ALTER TABLE stackbone_platform.run_steps
|
|
15
|
+
ADD CONSTRAINT run_steps_type_check
|
|
16
|
+
CHECK (type IN (
|
|
17
|
+
'workflow_step', 'model_call', 'connection', 'hook',
|
|
18
|
+
'tool_call', 'agent', 'guardrail', 'voice'
|
|
19
|
+
));
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
-- 0121_model_routing.sql — the OpenRouter provider routing an operator picked
|
|
2
|
+
-- for one model key of one deep agent (`provider: { sort }` on its model calls).
|
|
3
|
+
--
|
|
4
|
+
-- Addressed like `model_selections` (0073), by (owner_kind, owner_name, key), but
|
|
5
|
+
-- its own table: `model_selections.model_id` is NOT NULL, and an agent that runs
|
|
6
|
+
-- on the model its code names still needs a routing row. No row means the code's
|
|
7
|
+
-- `modelRouting`, and with none written there, OpenRouter's default routing.
|
|
8
|
+
--
|
|
9
|
+
-- `sort` carries NO CHECK, for the reason 0073 has none on `owner_kind`: a box
|
|
10
|
+
-- running an older build must be able to store a value it cannot apply, and the
|
|
11
|
+
-- SDK ignores a sort it does not know.
|
|
12
|
+
CREATE TABLE IF NOT EXISTS stackbone_platform.model_routing (
|
|
13
|
+
owner_kind text NOT NULL,
|
|
14
|
+
owner_name text NOT NULL,
|
|
15
|
+
key text NOT NULL,
|
|
16
|
+
sort text NOT NULL,
|
|
17
|
+
updated_by text,
|
|
18
|
+
updated_at timestamptz NOT NULL DEFAULT now(),
|
|
19
|
+
PRIMARY KEY (owner_kind, owner_name, key)
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
-- The voice settings leaf `fastModelRouting` is retired: provider routing now
|
|
23
|
+
-- belongs to the agent's model keys. The settings schema is strict, so a stored
|
|
24
|
+
-- override still holding the key would fail every read of that agent's settings.
|
|
25
|
+
-- It never reached production, so the value is dropped rather than carried over.
|
|
26
|
+
UPDATE stackbone_platform.voice_settings
|
|
27
|
+
SET overrides = overrides - 'fastModelRouting'
|
|
28
|
+
WHERE overrides ? 'fastModelRouting';
|
package/package.json
CHANGED
|
Binary file
|